1 // SPDX-License-Identifier: MIT
2
3 //! This is a simple QR encoder for DRM panic.
4 //!
5 //! It is called from a panic handler, so it should't allocate memory and
6 //! does all the work on the stack or on the provided buffers. For
7 //! simplification, it only supports low error correction, and applies the
8 //! first mask (checkerboard). It will draw the smallest QR code that can
9 //! contain the string passed as parameter. To get the most compact
10 //! QR code, the start of the URL is encoded as binary, and the
11 //! compressed kmsg is encoded as numeric.
12 //!
13 //! The binary data must be a valid URL parameter, so the easiest way is
14 //! to use base64 encoding. But this wastes 25% of data space, so the
15 //! whole stack trace won't fit in the QR code. So instead it encodes
16 //! every 7 bytes of input into 17 decimal digits, and then uses the
17 //! efficient numeric encoding, that encode 3 decimal digits into
18 //! 10bits. This makes 168bits of compressed data into 51 decimal digits,
19 //! into 170bits in the QR code, so wasting only 1.17%. And the numbers are
20 //! valid URL parameter, so the website can do the reverse, to get the
21 //! binary data. This is the same algorithm used by Fido v2.2 QR-initiated
22 //! authentication specification.
23 //!
24 //! Inspired by these 3 projects, all under MIT license:
25 //!
26 //! * <https://github.com/kennytm/qrcode-rust>
27 //! * <https://github.com/erwanvivien/fast_qr>
28 //! * <https://github.com/bjguillot/qr>
29
30 use kernel::prelude::*;
31
32 #[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd)]
33 struct Version(usize);
34
35 // Generator polynomials for ECC, only those that are needed for low quality.
36 const P7: [u8; 7] = [87, 229, 146, 149, 238, 102, 21];
37 const P10: [u8; 10] = [251, 67, 46, 61, 118, 70, 64, 94, 32, 45];
38 const P15: [u8; 15] = [
39 8, 183, 61, 91, 202, 37, 51, 58, 58, 237, 140, 124, 5, 99, 105,
40 ];
41 const P18: [u8; 18] = [
42 215, 234, 158, 94, 184, 97, 118, 170, 79, 187, 152, 148, 252, 179, 5, 98, 96, 153,
43 ];
44 const P20: [u8; 20] = [
45 17, 60, 79, 50, 61, 163, 26, 187, 202, 180, 221, 225, 83, 239, 156, 164, 212, 212, 188, 190,
46 ];
47 const P22: [u8; 22] = [
48 210, 171, 247, 242, 93, 230, 14, 109, 221, 53, 200, 74, 8, 172, 98, 80, 219, 134, 160, 105,
49 165, 231,
50 ];
51 const P24: [u8; 24] = [
52 229, 121, 135, 48, 211, 117, 251, 126, 159, 180, 169, 152, 192, 226, 228, 218, 111, 0, 117,
53 232, 87, 96, 227, 21,
54 ];
55 const P26: [u8; 26] = [
56 173, 125, 158, 2, 103, 182, 118, 17, 145, 201, 111, 28, 165, 53, 161, 21, 245, 142, 13, 102,
57 48, 227, 153, 145, 218, 70,
58 ];
59 const P28: [u8; 28] = [
60 168, 223, 200, 104, 224, 234, 108, 180, 110, 190, 195, 147, 205, 27, 232, 201, 21, 43, 245, 87,
61 42, 195, 212, 119, 242, 37, 9, 123,
62 ];
63 const P30: [u8; 30] = [
64 41, 173, 145, 152, 216, 31, 179, 182, 50, 48, 110, 86, 239, 96, 222, 125, 42, 173, 226, 193,
65 224, 130, 156, 37, 251, 216, 238, 40, 192, 180,
66 ];
67
68 /// QR Code parameters for Low quality ECC:
69 /// - Error Correction polynomial.
70 /// - Number of blocks in group 1.
71 /// - Number of blocks in group 2.
72 /// - Block size in group 1.
73 ///
74 /// (Block size in group 2 is one more than group 1).
75 struct VersionParameter(&'static [u8], u8, u8, u8);
76 const VPARAM: [VersionParameter; 40] = [
77 VersionParameter(&P7, 1, 0, 19), // V1
78 VersionParameter(&P10, 1, 0, 34), // V2
79 VersionParameter(&P15, 1, 0, 55), // V3
80 VersionParameter(&P20, 1, 0, 80), // V4
81 VersionParameter(&P26, 1, 0, 108), // V5
82 VersionParameter(&P18, 2, 0, 68), // V6
83 VersionParameter(&P20, 2, 0, 78), // V7
84 VersionParameter(&P24, 2, 0, 97), // V8
85 VersionParameter(&P30, 2, 0, 116), // V9
86 VersionParameter(&P18, 2, 2, 68), // V10
87 VersionParameter(&P20, 4, 0, 81), // V11
88 VersionParameter(&P24, 2, 2, 92), // V12
89 VersionParameter(&P26, 4, 0, 107), // V13
90 VersionParameter(&P30, 3, 1, 115), // V14
91 VersionParameter(&P22, 5, 1, 87), // V15
92 VersionParameter(&P24, 5, 1, 98), // V16
93 VersionParameter(&P28, 1, 5, 107), // V17
94 VersionParameter(&P30, 5, 1, 120), // V18
95 VersionParameter(&P28, 3, 4, 113), // V19
96 VersionParameter(&P28, 3, 5, 107), // V20
97 VersionParameter(&P28, 4, 4, 116), // V21
98 VersionParameter(&P28, 2, 7, 111), // V22
99 VersionParameter(&P30, 4, 5, 121), // V23
100 VersionParameter(&P30, 6, 4, 117), // V24
101 VersionParameter(&P26, 8, 4, 106), // V25
102 VersionParameter(&P28, 10, 2, 114), // V26
103 VersionParameter(&P30, 8, 4, 122), // V27
104 VersionParameter(&P30, 3, 10, 117), // V28
105 VersionParameter(&P30, 7, 7, 116), // V29
106 VersionParameter(&P30, 5, 10, 115), // V30
107 VersionParameter(&P30, 13, 3, 115), // V31
108 VersionParameter(&P30, 17, 0, 115), // V32
109 VersionParameter(&P30, 17, 1, 115), // V33
110 VersionParameter(&P30, 13, 6, 115), // V34
111 VersionParameter(&P30, 12, 7, 121), // V35
112 VersionParameter(&P30, 6, 14, 121), // V36
113 VersionParameter(&P30, 17, 4, 122), // V37
114 VersionParameter(&P30, 4, 18, 122), // V38
115 VersionParameter(&P30, 20, 4, 117), // V39
116 VersionParameter(&P30, 19, 6, 118), // V40
117 ];
118
119 const MAX_EC_SIZE: usize = 30;
120 const MAX_BLK_SIZE: usize = 123;
121
122 /// Position of the alignment pattern grid.
123 const ALIGNMENT_PATTERNS: [&[u8]; 40] = [
124 &[],
125 &[6, 18],
126 &[6, 22],
127 &[6, 26],
128 &[6, 30],
129 &[6, 34],
130 &[6, 22, 38],
131 &[6, 24, 42],
132 &[6, 26, 46],
133 &[6, 28, 50],
134 &[6, 30, 54],
135 &[6, 32, 58],
136 &[6, 34, 62],
137 &[6, 26, 46, 66],
138 &[6, 26, 48, 70],
139 &[6, 26, 50, 74],
140 &[6, 30, 54, 78],
141 &[6, 30, 56, 82],
142 &[6, 30, 58, 86],
143 &[6, 34, 62, 90],
144 &[6, 28, 50, 72, 94],
145 &[6, 26, 50, 74, 98],
146 &[6, 30, 54, 78, 102],
147 &[6, 28, 54, 80, 106],
148 &[6, 32, 58, 84, 110],
149 &[6, 30, 58, 86, 114],
150 &[6, 34, 62, 90, 118],
151 &[6, 26, 50, 74, 98, 122],
152 &[6, 30, 54, 78, 102, 126],
153 &[6, 26, 52, 78, 104, 130],
154 &[6, 30, 56, 82, 108, 134],
155 &[6, 34, 60, 86, 112, 138],
156 &[6, 30, 58, 86, 114, 142],
157 &[6, 34, 62, 90, 118, 146],
158 &[6, 30, 54, 78, 102, 126, 150],
159 &[6, 24, 50, 76, 102, 128, 154],
160 &[6, 28, 54, 80, 106, 132, 158],
161 &[6, 32, 58, 84, 110, 136, 162],
162 &[6, 26, 54, 82, 110, 138, 166],
163 &[6, 30, 58, 86, 114, 142, 170],
164 ];
165
166 /// Version information for format V7-V40.
167 const VERSION_INFORMATION: [u32; 34] = [
168 0b00_0111_1100_1001_0100,
169 0b00_1000_0101_1011_1100,
170 0b00_1001_1010_1001_1001,
171 0b00_1010_0100_1101_0011,
172 0b00_1011_1011_1111_0110,
173 0b00_1100_0111_0110_0010,
174 0b00_1101_1000_0100_0111,
175 0b00_1110_0110_0000_1101,
176 0b00_1111_1001_0010_1000,
177 0b01_0000_1011_0111_1000,
178 0b01_0001_0100_0101_1101,
179 0b01_0010_1010_0001_0111,
180 0b01_0011_0101_0011_0010,
181 0b01_0100_1001_1010_0110,
182 0b01_0101_0110_1000_0011,
183 0b01_0110_1000_1100_1001,
184 0b01_0111_0111_1110_1100,
185 0b01_1000_1110_1100_0100,
186 0b01_1001_0001_1110_0001,
187 0b01_1010_1111_1010_1011,
188 0b01_1011_0000_1000_1110,
189 0b01_1100_1100_0001_1010,
190 0b01_1101_0011_0011_1111,
191 0b01_1110_1101_0111_0101,
192 0b01_1111_0010_0101_0000,
193 0b10_0000_1001_1101_0101,
194 0b10_0001_0110_1111_0000,
195 0b10_0010_1000_1011_1010,
196 0b10_0011_0111_1001_1111,
197 0b10_0100_1011_0000_1011,
198 0b10_0101_0100_0010_1110,
199 0b10_0110_1010_0110_0100,
200 0b10_0111_0101_0100_0001,
201 0b10_1000_1100_0110_1001,
202 ];
203
204 /// Format info for low quality ECC.
205 const FORMAT_INFOS_QR_L: [u16; 8] = [
206 0x77c4, 0x72f3, 0x7daa, 0x789d, 0x662f, 0x6318, 0x6c41, 0x6976,
207 ];
208
209 impl Version {
210 /// Returns the smallest QR version than can hold these segments.
from_segments(segments: &[&Segment<'_>]) -> Option<Version>211 fn from_segments(segments: &[&Segment<'_>]) -> Option<Version> {
212 (1..=40)
213 .map(Version)
214 .find(|&v| v.max_data() * 8 >= segments.iter().map(|s| s.total_size_bits(v)).sum())
215 }
216
width(&self) -> u8217 fn width(&self) -> u8 {
218 (self.0 as u8) * 4 + 17
219 }
220
max_data(&self) -> usize221 fn max_data(&self) -> usize {
222 self.g1_blk_size() * self.g1_blocks() + (self.g1_blk_size() + 1) * self.g2_blocks()
223 }
224
ec_size(&self) -> usize225 fn ec_size(&self) -> usize {
226 VPARAM[self.0 - 1].0.len()
227 }
228
g1_blocks(&self) -> usize229 fn g1_blocks(&self) -> usize {
230 VPARAM[self.0 - 1].1 as usize
231 }
232
g2_blocks(&self) -> usize233 fn g2_blocks(&self) -> usize {
234 VPARAM[self.0 - 1].2 as usize
235 }
236
g1_blk_size(&self) -> usize237 fn g1_blk_size(&self) -> usize {
238 VPARAM[self.0 - 1].3 as usize
239 }
240
alignment_pattern(&self) -> &'static [u8]241 fn alignment_pattern(&self) -> &'static [u8] {
242 ALIGNMENT_PATTERNS[self.0 - 1]
243 }
244
poly(&self) -> &'static [u8]245 fn poly(&self) -> &'static [u8] {
246 VPARAM[self.0 - 1].0
247 }
248
version_info(&self) -> u32249 fn version_info(&self) -> u32 {
250 if *self >= Version(7) {
251 VERSION_INFORMATION[self.0 - 7]
252 } else {
253 0
254 }
255 }
256 }
257
258 /// Exponential table for Galois Field GF(256).
259 const EXP_TABLE: [u8; 256] = [
260 1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117,
261 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181,
262 119, 238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111, 222, 161,
263 95, 190, 97, 194, 153, 47, 94, 188, 101, 202, 137, 15, 30, 60, 120, 240, 253, 231, 211, 187,
264 107, 214, 177, 127, 254, 225, 223, 163, 91, 182, 113, 226, 217, 175, 67, 134, 17, 34, 68, 136,
265 13, 26, 52, 104, 208, 189, 103, 206, 129, 31, 62, 124, 248, 237, 199, 147, 59, 118, 236, 197,
266 151, 51, 102, 204, 133, 23, 46, 92, 184, 109, 218, 169, 79, 158, 33, 66, 132, 21, 42, 84, 168,
267 77, 154, 41, 82, 164, 85, 170, 73, 146, 57, 114, 228, 213, 183, 115, 230, 209, 191, 99, 198,
268 145, 63, 126, 252, 229, 215, 179, 123, 246, 241, 255, 227, 219, 171, 75, 150, 49, 98, 196, 149,
269 55, 110, 220, 165, 87, 174, 65, 130, 25, 50, 100, 200, 141, 7, 14, 28, 56, 112, 224, 221, 167,
270 83, 166, 81, 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86, 172, 69, 138, 9, 18, 36, 72,
271 144, 61, 122, 244, 245, 247, 243, 251, 235, 203, 139, 11, 22, 44, 88, 176, 125, 250, 233, 207,
272 131, 27, 54, 108, 216, 173, 71, 142, 1,
273 ];
274
275 /// Reverse exponential table for Galois Field GF(256).
276 const LOG_TABLE: [u8; 256] = [
277 175, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75, 4, 100, 224, 14, 52, 141,
278 239, 129, 28, 193, 105, 248, 200, 8, 76, 113, 5, 138, 101, 47, 225, 36, 15, 33, 53, 147, 142,
279 218, 240, 18, 130, 69, 29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9, 120, 77, 228, 114,
280 166, 6, 191, 139, 98, 102, 221, 48, 253, 226, 152, 37, 179, 16, 145, 34, 136, 54, 208, 148,
281 206, 143, 150, 219, 189, 241, 210, 19, 92, 131, 56, 70, 64, 30, 66, 182, 163, 195, 72, 126,
282 110, 107, 58, 40, 84, 250, 133, 186, 61, 202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172,
283 115, 243, 167, 87, 7, 112, 192, 247, 140, 128, 99, 13, 103, 74, 222, 237, 49, 197, 254, 24,
284 227, 165, 153, 119, 38, 184, 180, 124, 17, 68, 146, 217, 35, 32, 137, 46, 55, 63, 209, 91, 149,
285 188, 207, 205, 144, 135, 151, 178, 220, 252, 190, 97, 242, 86, 211, 171, 20, 42, 93, 158, 132,
286 60, 57, 83, 71, 109, 65, 162, 31, 45, 67, 216, 183, 123, 164, 118, 196, 23, 73, 236, 127, 12,
287 111, 246, 108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134, 177, 187, 204, 62, 90, 203, 89, 95,
288 176, 156, 169, 160, 81, 11, 245, 22, 235, 122, 117, 44, 215, 79, 174, 213, 233, 230, 231, 173,
289 232, 116, 214, 244, 234, 168, 80, 88, 175,
290 ];
291
292 // 4 bits segment header.
293 const MODE_STOP: u16 = 0;
294 const MODE_NUMERIC: u16 = 1;
295 const MODE_BINARY: u16 = 4;
296 /// Padding bytes.
297 const PADDING: [u8; 2] = [236, 17];
298
299 /// Number of bits to encode characters in numeric mode.
300 const NUM_CHARS_BITS: [usize; 4] = [0, 4, 7, 10];
301 /// Number of decimal digits required to encode n bytes of binary data.
302 /// eg: you need 15 decimal digits to fit 6 bytes of binary data.
303 const BYTES_TO_DIGITS: [usize; 8] = [0, 3, 5, 8, 10, 13, 15, 17];
304
305 enum Segment<'a> {
306 Numeric(&'a [u8]),
307 Binary(&'a [u8]),
308 }
309
310 impl Segment<'_> {
get_header(&self) -> (u16, usize)311 fn get_header(&self) -> (u16, usize) {
312 match self {
313 Segment::Binary(_) => (MODE_BINARY, 4),
314 Segment::Numeric(_) => (MODE_NUMERIC, 4),
315 }
316 }
317
318 /// Returns the size of the length field in bits, depending on QR Version.
length_bits_count(&self, version: Version) -> usize319 fn length_bits_count(&self, version: Version) -> usize {
320 let Version(v) = version;
321 match self {
322 Segment::Binary(_) => match v {
323 1..=9 => 8,
324 _ => 16,
325 },
326 Segment::Numeric(_) => match v {
327 1..=9 => 10,
328 10..=26 => 12,
329 _ => 14,
330 },
331 }
332 }
333
334 /// Number of characters in the segment.
character_count(&self) -> usize335 fn character_count(&self) -> usize {
336 match self {
337 Segment::Binary(data) => data.len(),
338 Segment::Numeric(data) => {
339 let last_chars = BYTES_TO_DIGITS[data.len() % 7];
340 // 17 decimal numbers per 7bytes + remainder.
341 17 * (data.len() / 7) + last_chars
342 }
343 }
344 }
345
get_length_field(&self, version: Version) -> (u16, usize)346 fn get_length_field(&self, version: Version) -> (u16, usize) {
347 (
348 self.character_count() as u16,
349 self.length_bits_count(version),
350 )
351 }
352
total_size_bits(&self, version: Version) -> usize353 fn total_size_bits(&self, version: Version) -> usize {
354 let data_size = match self {
355 Segment::Binary(data) => data.len() * 8,
356 Segment::Numeric(_) => {
357 let digits = self.character_count();
358 10 * (digits / 3) + NUM_CHARS_BITS[digits % 3]
359 }
360 };
361 // header + length + data.
362 4 + self.length_bits_count(version) + data_size
363 }
364
iter(&self) -> SegmentIterator<'_>365 fn iter(&self) -> SegmentIterator<'_> {
366 SegmentIterator {
367 segment: self,
368 offset: 0,
369 decfifo: Default::default(),
370 }
371 }
372 }
373
374 /// Max fifo size is 17 (max push) + 2 (max remaining)
375 const MAX_FIFO_SIZE: usize = 19;
376
377 /// A simple Decimal digit FIFO
378 #[derive(Default)]
379 struct DecFifo {
380 decimals: [u8; MAX_FIFO_SIZE],
381 len: usize,
382 }
383
384 // On arm32 architecture, dividing an `u64` by a constant will generate a call
385 // to `__aeabi_uldivmod` which is not present in the kernel.
386 // So use the multiply by inverse method for this architecture.
div10(val: u64) -> u64387 fn div10(val: u64) -> u64 {
388 if cfg!(target_arch = "arm") {
389 let val_h = val >> 32;
390 let val_l = val & 0xFFFFFFFF;
391 let b_h: u64 = 0x66666666;
392 let b_l: u64 = 0x66666667;
393
394 let tmp1 = val_h * b_l + ((val_l * b_l) >> 32);
395 let tmp2 = val_l * b_h + (tmp1 & 0xffffffff);
396 let tmp3 = val_h * b_h + (tmp1 >> 32) + (tmp2 >> 32);
397
398 tmp3 >> 2
399 } else {
400 val / 10
401 }
402 }
403
404 impl DecFifo {
push(&mut self, data: u64, len: usize)405 fn push(&mut self, data: u64, len: usize) {
406 let mut chunk = data;
407 for i in (0..self.len).rev() {
408 self.decimals[i + len] = self.decimals[i];
409 }
410 for i in 0..len {
411 self.decimals[i] = (chunk % 10) as u8;
412 chunk = div10(chunk);
413 }
414 self.len += len;
415 }
416
417 /// Pop 3 decimal digits from the FIFO
pop3(&mut self) -> Option<(u16, usize)>418 fn pop3(&mut self) -> Option<(u16, usize)> {
419 if self.len == 0 {
420 None
421 } else {
422 let poplen = 3.min(self.len);
423 self.len -= poplen;
424 let mut out = 0;
425 let mut exp = 1;
426 for i in 0..poplen {
427 out += u16::from(self.decimals[self.len + i]) * exp;
428 exp *= 10;
429 }
430 Some((out, NUM_CHARS_BITS[poplen]))
431 }
432 }
433 }
434
435 struct SegmentIterator<'a> {
436 segment: &'a Segment<'a>,
437 offset: usize,
438 decfifo: DecFifo,
439 }
440
441 impl Iterator for SegmentIterator<'_> {
442 type Item = (u16, usize);
443
next(&mut self) -> Option<Self::Item>444 fn next(&mut self) -> Option<Self::Item> {
445 match self.segment {
446 Segment::Binary(data) => {
447 if self.offset < data.len() {
448 let byte = u16::from(data[self.offset]);
449 self.offset += 1;
450 Some((byte, 8))
451 } else {
452 None
453 }
454 }
455 Segment::Numeric(data) => {
456 if self.decfifo.len < 3 && self.offset < data.len() {
457 // If there are less than 3 decimal digits in the fifo,
458 // take the next 7 bytes of input, and push them to the fifo.
459 let mut buf = [0u8; 8];
460 let len = 7.min(data.len() - self.offset);
461 buf[..len].copy_from_slice(&data[self.offset..self.offset + len]);
462 let chunk = u64::from_le_bytes(buf);
463 self.decfifo.push(chunk, BYTES_TO_DIGITS[len]);
464 self.offset += len;
465 }
466 self.decfifo.pop3()
467 }
468 }
469 }
470 }
471
472 struct EncodedMsg<'a> {
473 data: &'a mut [u8],
474 ec_size: usize,
475 g1_blocks: usize,
476 g2_blocks: usize,
477 g1_blk_size: usize,
478 g2_blk_size: usize,
479 poly: &'static [u8],
480 version: Version,
481 }
482
483 /// Data to be put in the QR code, with correct segment encoding, padding, and
484 /// Error Code Correction.
485 impl EncodedMsg<'_> {
new<'a>(segments: &[&Segment<'_>], data: &'a mut [u8]) -> Option<EncodedMsg<'a>>486 fn new<'a>(segments: &[&Segment<'_>], data: &'a mut [u8]) -> Option<EncodedMsg<'a>> {
487 let version = Version::from_segments(segments)?;
488 let ec_size = version.ec_size();
489 let g1_blocks = version.g1_blocks();
490 let g2_blocks = version.g2_blocks();
491 let g1_blk_size = version.g1_blk_size();
492 let g2_blk_size = g1_blk_size + 1;
493 let poly = version.poly();
494
495 // clear the output.
496 data.fill(0);
497
498 let mut em = EncodedMsg {
499 data,
500 ec_size,
501 g1_blocks,
502 g2_blocks,
503 g1_blk_size,
504 g2_blk_size,
505 poly,
506 version,
507 };
508 em.encode(segments);
509 Some(em)
510 }
511
512 /// Push bits of data at an offset (in bits).
push(&mut self, offset: &mut usize, bits: (u16, usize))513 fn push(&mut self, offset: &mut usize, bits: (u16, usize)) {
514 let (number, len_bits) = bits;
515 let byte_off = *offset / 8;
516 let bit_off = *offset % 8;
517 let b = bit_off + len_bits;
518
519 match (bit_off, b) {
520 (0, 0..=8) => {
521 self.data[byte_off] = (number << (8 - b)) as u8;
522 }
523 (0, _) => {
524 self.data[byte_off] = (number >> (b - 8)) as u8;
525 self.data[byte_off + 1] = (number << (16 - b)) as u8;
526 }
527 (_, 0..=8) => {
528 self.data[byte_off] |= (number << (8 - b)) as u8;
529 }
530 (_, 9..=16) => {
531 self.data[byte_off] |= (number >> (b - 8)) as u8;
532 self.data[byte_off + 1] = (number << (16 - b)) as u8;
533 }
534 _ => {
535 self.data[byte_off] |= (number >> (b - 8)) as u8;
536 self.data[byte_off + 1] = (number >> (b - 16)) as u8;
537 self.data[byte_off + 2] = (number << (24 - b)) as u8;
538 }
539 }
540 *offset += len_bits;
541 }
542
add_segments(&mut self, segments: &[&Segment<'_>])543 fn add_segments(&mut self, segments: &[&Segment<'_>]) {
544 let mut offset: usize = 0;
545
546 for s in segments.iter() {
547 self.push(&mut offset, s.get_header());
548 self.push(&mut offset, s.get_length_field(self.version));
549 for bits in s.iter() {
550 self.push(&mut offset, bits);
551 }
552 }
553 self.push(&mut offset, (MODE_STOP, 4));
554
555 let pad_offset = offset.div_ceil(8);
556 for i in pad_offset..self.version.max_data() {
557 self.data[i] = PADDING[(i & 1) ^ (pad_offset & 1)];
558 }
559 }
560
error_code_for_blocks(&mut self, offset: usize, size: usize, ec_offset: usize)561 fn error_code_for_blocks(&mut self, offset: usize, size: usize, ec_offset: usize) {
562 let mut tmp: [u8; MAX_BLK_SIZE + MAX_EC_SIZE] = [0; MAX_BLK_SIZE + MAX_EC_SIZE];
563
564 tmp[0..size].copy_from_slice(&self.data[offset..offset + size]);
565 for i in 0..size {
566 let lead_coeff = tmp[i] as usize;
567 if lead_coeff == 0 {
568 continue;
569 }
570 let log_lead_coeff = usize::from(LOG_TABLE[lead_coeff]);
571 for (u, &v) in tmp[i + 1..].iter_mut().zip(self.poly.iter()) {
572 *u ^= EXP_TABLE[(usize::from(v) + log_lead_coeff) % 255];
573 }
574 }
575 self.data[ec_offset..ec_offset + self.ec_size]
576 .copy_from_slice(&tmp[size..size + self.ec_size]);
577 }
578
compute_error_code(&mut self)579 fn compute_error_code(&mut self) {
580 let mut offset = 0;
581 let mut ec_offset = self.g1_blocks * self.g1_blk_size + self.g2_blocks * self.g2_blk_size;
582
583 for _ in 0..self.g1_blocks {
584 self.error_code_for_blocks(offset, self.g1_blk_size, ec_offset);
585 offset += self.g1_blk_size;
586 ec_offset += self.ec_size;
587 }
588 for _ in 0..self.g2_blocks {
589 self.error_code_for_blocks(offset, self.g2_blk_size, ec_offset);
590 offset += self.g2_blk_size;
591 ec_offset += self.ec_size;
592 }
593 }
594
encode(&mut self, segments: &[&Segment<'_>])595 fn encode(&mut self, segments: &[&Segment<'_>]) {
596 self.add_segments(segments);
597 self.compute_error_code();
598 }
599
iter(&self) -> EncodedMsgIterator<'_>600 fn iter(&self) -> EncodedMsgIterator<'_> {
601 EncodedMsgIterator {
602 em: self,
603 offset: 0,
604 }
605 }
606 }
607
608 /// Iterator, to retrieve the data in the interleaved order needed by QR code.
609 struct EncodedMsgIterator<'a> {
610 em: &'a EncodedMsg<'a>,
611 offset: usize,
612 }
613
614 impl Iterator for EncodedMsgIterator<'_> {
615 type Item = u8;
616
617 /// Send the bytes in interleaved mode, first byte of first block of group1,
618 /// then first byte of second block of group1, ...
next(&mut self) -> Option<Self::Item>619 fn next(&mut self) -> Option<Self::Item> {
620 let em = self.em;
621 let blocks = em.g1_blocks + em.g2_blocks;
622 let g1_end = em.g1_blocks * em.g1_blk_size;
623 let g2_end = g1_end + em.g2_blocks * em.g2_blk_size;
624 let ec_end = g2_end + em.ec_size * blocks;
625
626 if self.offset >= ec_end {
627 return None;
628 }
629
630 let offset = if self.offset < em.g1_blk_size * blocks {
631 // group1 and group2 interleaved
632 let blk = self.offset % blocks;
633 let blk_off = self.offset / blocks;
634 if blk < em.g1_blocks {
635 blk * em.g1_blk_size + blk_off
636 } else {
637 g1_end + em.g2_blk_size * (blk - em.g1_blocks) + blk_off
638 }
639 } else if self.offset < g2_end {
640 // last byte of group2 blocks
641 let blk2 = self.offset - blocks * em.g1_blk_size;
642 em.g1_blk_size * em.g1_blocks + blk2 * em.g2_blk_size + em.g2_blk_size - 1
643 } else {
644 // EC blocks
645 let ec_offset = self.offset - g2_end;
646 let blk = ec_offset % blocks;
647 let blk_off = ec_offset / blocks;
648
649 g2_end + blk * em.ec_size + blk_off
650 };
651 self.offset += 1;
652 Some(em.data[offset])
653 }
654 }
655
656 /// A QR code image, encoded as a linear binary framebuffer.
657 /// 1 bit per module (pixel), each new line start at next byte boundary.
658 /// Max width is 177 for V40 QR code, so `u8` is enough for coordinate.
659 struct QrImage<'a> {
660 data: &'a mut [u8],
661 width: u8,
662 stride: u8,
663 version: Version,
664 }
665
666 impl QrImage<'_> {
new<'a, 'b>(em: &'b EncodedMsg<'b>, qrdata: &'a mut [u8]) -> QrImage<'a>667 fn new<'a, 'b>(em: &'b EncodedMsg<'b>, qrdata: &'a mut [u8]) -> QrImage<'a> {
668 let width = em.version.width();
669 let stride = width.div_ceil(8);
670 let data = qrdata;
671
672 let mut qr_image = QrImage {
673 data,
674 width,
675 stride,
676 version: em.version,
677 };
678 qr_image.draw_all(em.iter());
679 qr_image
680 }
681
clear(&mut self)682 fn clear(&mut self) {
683 self.data.fill(0);
684 }
685
686 /// Set pixel to light color.
set(&mut self, x: u8, y: u8)687 fn set(&mut self, x: u8, y: u8) {
688 let off = y as usize * self.stride as usize + x as usize / 8;
689 let mut v = self.data[off];
690 v |= 0x80 >> (x % 8);
691 self.data[off] = v;
692 }
693
694 /// Invert a module color.
xor(&mut self, x: u8, y: u8)695 fn xor(&mut self, x: u8, y: u8) {
696 let off = y as usize * self.stride as usize + x as usize / 8;
697 self.data[off] ^= 0x80 >> (x % 8);
698 }
699
700 /// Draw a light square at (x, y) top left corner.
draw_square(&mut self, x: u8, y: u8, size: u8)701 fn draw_square(&mut self, x: u8, y: u8, size: u8) {
702 for k in 0..size {
703 self.set(x + k, y);
704 self.set(x, y + k + 1);
705 self.set(x + size, y + k);
706 self.set(x + k + 1, y + size);
707 }
708 }
709
710 // Finder pattern: 3 8x8 square at the corners.
draw_finders(&mut self)711 fn draw_finders(&mut self) {
712 self.draw_square(1, 1, 4);
713 self.draw_square(self.width - 6, 1, 4);
714 self.draw_square(1, self.width - 6, 4);
715 for k in 0..8 {
716 self.set(k, 7);
717 self.set(self.width - k - 1, 7);
718 self.set(k, self.width - 8);
719 }
720 for k in 0..7 {
721 self.set(7, k);
722 self.set(self.width - 8, k);
723 self.set(7, self.width - 1 - k);
724 }
725 }
726
is_finder(&self, x: u8, y: u8) -> bool727 fn is_finder(&self, x: u8, y: u8) -> bool {
728 let end = self.width - 8;
729 #[expect(clippy::nonminimal_bool)]
730 {
731 (x < 8 && y < 8) || (x < 8 && y >= end) || (x >= end && y < 8)
732 }
733 }
734
735 // Alignment pattern: 5x5 squares in a grid.
draw_alignments(&mut self)736 fn draw_alignments(&mut self) {
737 let positions = self.version.alignment_pattern();
738 for &x in positions.iter() {
739 for &y in positions.iter() {
740 if !self.is_finder(x, y) {
741 self.draw_square(x - 1, y - 1, 2);
742 }
743 }
744 }
745 }
746
is_alignment(&self, x: u8, y: u8) -> bool747 fn is_alignment(&self, x: u8, y: u8) -> bool {
748 let positions = self.version.alignment_pattern();
749 for &ax in positions.iter() {
750 for &ay in positions.iter() {
751 if self.is_finder(ax, ay) {
752 continue;
753 }
754 if x >= ax - 2 && x <= ax + 2 && y >= ay - 2 && y <= ay + 2 {
755 return true;
756 }
757 }
758 }
759 false
760 }
761
762 // Timing pattern: 2 dotted line between the finder patterns.
draw_timing_patterns(&mut self)763 fn draw_timing_patterns(&mut self) {
764 let end = self.width - 8;
765
766 for x in (9..end).step_by(2) {
767 self.set(x, 6);
768 self.set(6, x);
769 }
770 }
771
is_timing(&self, x: u8, y: u8) -> bool772 fn is_timing(&self, x: u8, y: u8) -> bool {
773 x == 6 || y == 6
774 }
775
776 // Mask info: 15 bits around the finders, written twice for redundancy.
draw_maskinfo(&mut self)777 fn draw_maskinfo(&mut self) {
778 let info: u16 = FORMAT_INFOS_QR_L[0];
779 let mut skip = 0;
780
781 for k in 0..7 {
782 if k == 6 {
783 skip = 1;
784 }
785 if info & (1 << (14 - k)) == 0 {
786 self.set(k + skip, 8);
787 self.set(8, self.width - 1 - k);
788 }
789 }
790 skip = 0;
791 for k in 0..8 {
792 if k == 2 {
793 skip = 1;
794 }
795 if info & (1 << (7 - k)) == 0 {
796 self.set(8, 8 - skip - k);
797 self.set(self.width - 8 + k, 8);
798 }
799 }
800 }
801
is_maskinfo(&self, x: u8, y: u8) -> bool802 fn is_maskinfo(&self, x: u8, y: u8) -> bool {
803 let end = self.width - 8;
804 // Count the dark module as mask info.
805 (x <= 8 && y == 8) || (y <= 8 && x == 8) || (x == 8 && y >= end) || (x >= end && y == 8)
806 }
807
808 // Version info: 18bits written twice, close to the finders.
draw_version_info(&mut self)809 fn draw_version_info(&mut self) {
810 let vinfo = self.version.version_info();
811 let pos = self.width - 11;
812
813 if vinfo != 0 {
814 for x in 0..3 {
815 for y in 0..6 {
816 if vinfo & (1 << (x + y * 3)) == 0 {
817 self.set(x + pos, y);
818 self.set(y, x + pos);
819 }
820 }
821 }
822 }
823 }
824
is_version_info(&self, x: u8, y: u8) -> bool825 fn is_version_info(&self, x: u8, y: u8) -> bool {
826 let vinfo = self.version.version_info();
827 let pos = self.width - 11;
828
829 vinfo != 0 && ((x >= pos && x < pos + 3 && y < 6) || (y >= pos && y < pos + 3 && x < 6))
830 }
831
832 /// Returns true if the module is reserved (Not usable for data and EC).
is_reserved(&self, x: u8, y: u8) -> bool833 fn is_reserved(&self, x: u8, y: u8) -> bool {
834 self.is_alignment(x, y)
835 || self.is_finder(x, y)
836 || self.is_timing(x, y)
837 || self.is_maskinfo(x, y)
838 || self.is_version_info(x, y)
839 }
840
841 /// Last module to draw, at bottom left corner.
is_last(&self, x: u8, y: u8) -> bool842 fn is_last(&self, x: u8, y: u8) -> bool {
843 x == 0 && y == self.width - 1
844 }
845
846 /// Move to the next module according to QR code order.
847 ///
848 /// From bottom right corner, to bottom left corner.
next(&self, x: u8, y: u8) -> (u8, u8)849 fn next(&self, x: u8, y: u8) -> (u8, u8) {
850 let x_adj = if x <= 6 { x + 1 } else { x };
851 let column_type = (self.width - x_adj) % 4;
852
853 match column_type {
854 2 if y > 0 => (x + 1, y - 1),
855 0 if y < self.width - 1 => (x + 1, y + 1),
856 0 | 2 if x == 7 => (x - 2, y),
857 _ => (x - 1, y),
858 }
859 }
860
861 /// Find next module that can hold data.
next_available(&self, x: u8, y: u8) -> (u8, u8)862 fn next_available(&self, x: u8, y: u8) -> (u8, u8) {
863 let (mut x, mut y) = self.next(x, y);
864 while self.is_reserved(x, y) && !self.is_last(x, y) {
865 (x, y) = self.next(x, y);
866 }
867 (x, y)
868 }
869
draw_data(&mut self, data: impl Iterator<Item = u8>)870 fn draw_data(&mut self, data: impl Iterator<Item = u8>) {
871 let (mut x, mut y) = (self.width - 1, self.width - 1);
872 for byte in data {
873 for s in 0..8 {
874 if byte & (0x80 >> s) == 0 {
875 self.set(x, y);
876 }
877 (x, y) = self.next_available(x, y);
878 }
879 }
880 // Set the remaining modules (0, 3 or 7 depending on version).
881 // because 0 correspond to a light module.
882 while !self.is_last(x, y) {
883 if !self.is_reserved(x, y) {
884 self.set(x, y);
885 }
886 (x, y) = self.next(x, y);
887 }
888 }
889
890 /// Apply checkerboard mask to all non-reserved modules.
apply_mask(&mut self)891 fn apply_mask(&mut self) {
892 for x in 0..self.width {
893 for y in 0..self.width {
894 if (x ^ y) % 2 == 0 && !self.is_reserved(x, y) {
895 self.xor(x, y);
896 }
897 }
898 }
899 }
900
901 /// Draw the QR code with the provided data iterator.
draw_all(&mut self, data: impl Iterator<Item = u8>)902 fn draw_all(&mut self, data: impl Iterator<Item = u8>) {
903 // First clear the table, as it may have already some data.
904 self.clear();
905 self.draw_finders();
906 self.draw_alignments();
907 self.draw_timing_patterns();
908 self.draw_version_info();
909 self.draw_data(data);
910 self.draw_maskinfo();
911 self.apply_mask();
912 }
913 }
914
915 /// C entry point for the rust QR Code generator.
916 ///
917 /// Write the QR code image in the data buffer, and return the QR code width,
918 /// or 0, if the data doesn't fit in a QR code.
919 ///
920 /// * `url`: The base URL of the QR code. It will be encoded as Binary segment.
921 /// * `data`: A pointer to the binary data, to be encoded. if URL is NULL, it
922 /// will be encoded as binary segment, otherwise it will be encoded
923 /// efficiently as a numeric segment, and appended to the URL.
924 /// * `data_len`: Length of the data, that needs to be encoded, must be less
925 /// than `data_size`.
926 /// * `data_size`: Size of data buffer, it should be at least 4071 bytes to hold
927 /// a V40 QR code. It will then be overwritten with the QR code image.
928 /// * `tmp`: A temporary buffer that the QR code encoder will use, to write the
929 /// segments and ECC.
930 /// * `tmp_size`: Size of the temporary buffer, it must be at least 3706 bytes
931 /// long for V40.
932 ///
933 /// # Safety
934 ///
935 /// * `url` must be null or point at a nul-terminated string.
936 /// * `data` must be valid for reading and writing for `data_size` bytes.
937 /// * `tmp` must be valid for reading and writing for `tmp_size` bytes.
938 ///
939 /// They must remain valid for the duration of the function call.
940 #[export]
drm_panic_qr_generate( url: *const kernel::ffi::c_char, data: *mut u8, data_len: usize, data_size: usize, tmp: *mut u8, tmp_size: usize, ) -> u8941 pub unsafe extern "C" fn drm_panic_qr_generate(
942 url: *const kernel::ffi::c_char,
943 data: *mut u8,
944 data_len: usize,
945 data_size: usize,
946 tmp: *mut u8,
947 tmp_size: usize,
948 ) -> u8 {
949 if data_size < 4071 || tmp_size < 3706 || data_len > data_size {
950 return 0;
951 }
952 // SAFETY: The caller ensures that `data` is a valid pointer for reading and
953 // writing `data_size` bytes.
954 let data_slice: &mut [u8] = unsafe { core::slice::from_raw_parts_mut(data, data_size) };
955 // SAFETY: The caller ensures that `tmp` is a valid pointer for reading and
956 // writing `tmp_size` bytes.
957 let tmp_slice: &mut [u8] = unsafe { core::slice::from_raw_parts_mut(tmp, tmp_size) };
958 if url.is_null() {
959 match EncodedMsg::new(&[&Segment::Binary(&data_slice[0..data_len])], tmp_slice) {
960 None => 0,
961 Some(em) => {
962 let qr_image = QrImage::new(&em, data_slice);
963 qr_image.width
964 }
965 }
966 } else {
967 // SAFETY: The caller ensures that `url` is a valid pointer to a
968 // nul-terminated string.
969 let url_cstr: &CStr = unsafe { CStr::from_char_ptr(url) };
970 let segments = &[
971 &Segment::Binary(url_cstr.as_bytes()),
972 &Segment::Numeric(&data_slice[0..data_len]),
973 ];
974 match EncodedMsg::new(segments, tmp_slice) {
975 None => 0,
976 Some(em) => {
977 let qr_image = QrImage::new(&em, data_slice);
978 qr_image.width
979 }
980 }
981 }
982 }
983
984 /// Returns the maximum data size that can fit in a QR code of this version.
985 /// * `version`: QR code version, between 1-40.
986 /// * `url_len`: Length of the URL.
987 ///
988 /// * If `url_len` > 0, remove the 2 segments header/length and also count the
989 /// conversion to numeric segments.
990 /// * If `url_len` = 0, only removes 3 bytes for 1 binary segment.
991 ///
992 /// # Safety
993 ///
994 /// Always safe to call.
995 // Required to be unsafe due to the `#[export]` annotation.
996 #[export]
drm_panic_qr_max_data_size(version: u8, url_len: usize) -> usize997 pub unsafe extern "C" fn drm_panic_qr_max_data_size(version: u8, url_len: usize) -> usize {
998 #[expect(clippy::manual_range_contains)]
999 if version < 1 || version > 40 {
1000 return 0;
1001 }
1002 let max_data = Version(version as usize).max_data();
1003
1004 if url_len > 0 {
1005 // Binary segment (URL) 4 + 16 bits, numeric segment (kmsg) 4 + 12 bits => 5 bytes.
1006 if url_len + 5 >= max_data {
1007 0
1008 } else {
1009 let max = max_data - url_len - 5;
1010 (max * 39) / 40
1011 }
1012 } else {
1013 // Remove 3 bytes for the binary segment (header 4 bits, length 16 bits, stop 4bits).
1014 max_data - 3
1015 }
1016 }
1017