xref: /linux/drivers/gpu/drm/drm_panic_qr.rs (revision 3c2fe27971c3c9cc27de6e369385f6428db6c0b5)
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 impl DecFifo {
push(&mut self, data: u64, len: usize)385     fn push(&mut self, data: u64, len: usize) {
386         let mut chunk = data;
387         for i in (0..self.len).rev() {
388             self.decimals[i + len] = self.decimals[i];
389         }
390         for i in 0..len {
391             self.decimals[i] = (chunk % 10) as u8;
392             chunk /= 10;
393         }
394         self.len += len;
395     }
396 
397     /// Pop 3 decimal digits from the FIFO
pop3(&mut self) -> Option<(u16, usize)>398     fn pop3(&mut self) -> Option<(u16, usize)> {
399         if self.len == 0 {
400             None
401         } else {
402             let poplen = 3.min(self.len);
403             self.len -= poplen;
404             let mut out = 0;
405             let mut exp = 1;
406             for i in 0..poplen {
407                 out += self.decimals[self.len + i] as u16 * exp;
408                 exp *= 10;
409             }
410             Some((out, NUM_CHARS_BITS[poplen]))
411         }
412     }
413 }
414 
415 struct SegmentIterator<'a> {
416     segment: &'a Segment<'a>,
417     offset: usize,
418     decfifo: DecFifo,
419 }
420 
421 impl Iterator for SegmentIterator<'_> {
422     type Item = (u16, usize);
423 
next(&mut self) -> Option<Self::Item>424     fn next(&mut self) -> Option<Self::Item> {
425         match self.segment {
426             Segment::Binary(data) => {
427                 if self.offset < data.len() {
428                     let byte = data[self.offset] as u16;
429                     self.offset += 1;
430                     Some((byte, 8))
431                 } else {
432                     None
433                 }
434             }
435             Segment::Numeric(data) => {
436                 if self.decfifo.len < 3 && self.offset < data.len() {
437                     // If there are less than 3 decimal digits in the fifo,
438                     // take the next 7 bytes of input, and push them to the fifo.
439                     let mut buf = [0u8; 8];
440                     let len = 7.min(data.len() - self.offset);
441                     buf[..len].copy_from_slice(&data[self.offset..self.offset + len]);
442                     let chunk = u64::from_le_bytes(buf);
443                     self.decfifo.push(chunk, BYTES_TO_DIGITS[len]);
444                     self.offset += len;
445                 }
446                 self.decfifo.pop3()
447             }
448         }
449     }
450 }
451 
452 struct EncodedMsg<'a> {
453     data: &'a mut [u8],
454     ec_size: usize,
455     g1_blocks: usize,
456     g2_blocks: usize,
457     g1_blk_size: usize,
458     g2_blk_size: usize,
459     poly: &'static [u8],
460     version: Version,
461 }
462 
463 /// Data to be put in the QR code, with correct segment encoding, padding, and
464 /// Error Code Correction.
465 impl EncodedMsg<'_> {
new<'a>(segments: &[&Segment<'_>], data: &'a mut [u8]) -> Option<EncodedMsg<'a>>466     fn new<'a>(segments: &[&Segment<'_>], data: &'a mut [u8]) -> Option<EncodedMsg<'a>> {
467         let version = Version::from_segments(segments)?;
468         let ec_size = version.ec_size();
469         let g1_blocks = version.g1_blocks();
470         let g2_blocks = version.g2_blocks();
471         let g1_blk_size = version.g1_blk_size();
472         let g2_blk_size = g1_blk_size + 1;
473         let poly = version.poly();
474 
475         // clear the output.
476         data.fill(0);
477 
478         let mut em = EncodedMsg {
479             data,
480             ec_size,
481             g1_blocks,
482             g2_blocks,
483             g1_blk_size,
484             g2_blk_size,
485             poly,
486             version,
487         };
488         em.encode(segments);
489         Some(em)
490     }
491 
492     /// Push bits of data at an offset (in bits).
push(&mut self, offset: &mut usize, bits: (u16, usize))493     fn push(&mut self, offset: &mut usize, bits: (u16, usize)) {
494         let (number, len_bits) = bits;
495         let byte_off = *offset / 8;
496         let bit_off = *offset % 8;
497         let b = bit_off + len_bits;
498 
499         match (bit_off, b) {
500             (0, 0..=8) => {
501                 self.data[byte_off] = (number << (8 - b)) as u8;
502             }
503             (0, _) => {
504                 self.data[byte_off] = (number >> (b - 8)) as u8;
505                 self.data[byte_off + 1] = (number << (16 - b)) as u8;
506             }
507             (_, 0..=8) => {
508                 self.data[byte_off] |= (number << (8 - b)) as u8;
509             }
510             (_, 9..=16) => {
511                 self.data[byte_off] |= (number >> (b - 8)) as u8;
512                 self.data[byte_off + 1] = (number << (16 - b)) as u8;
513             }
514             _ => {
515                 self.data[byte_off] |= (number >> (b - 8)) as u8;
516                 self.data[byte_off + 1] = (number >> (b - 16)) as u8;
517                 self.data[byte_off + 2] = (number << (24 - b)) as u8;
518             }
519         }
520         *offset += len_bits;
521     }
522 
add_segments(&mut self, segments: &[&Segment<'_>])523     fn add_segments(&mut self, segments: &[&Segment<'_>]) {
524         let mut offset: usize = 0;
525 
526         for s in segments.iter() {
527             self.push(&mut offset, s.get_header());
528             self.push(&mut offset, s.get_length_field(self.version));
529             for bits in s.iter() {
530                 self.push(&mut offset, bits);
531             }
532         }
533         self.push(&mut offset, (MODE_STOP, 4));
534 
535         let pad_offset = offset.div_ceil(8);
536         for i in pad_offset..self.version.max_data() {
537             self.data[i] = PADDING[(i & 1) ^ (pad_offset & 1)];
538         }
539     }
540 
error_code_for_blocks(&mut self, offset: usize, size: usize, ec_offset: usize)541     fn error_code_for_blocks(&mut self, offset: usize, size: usize, ec_offset: usize) {
542         let mut tmp: [u8; MAX_BLK_SIZE + MAX_EC_SIZE] = [0; MAX_BLK_SIZE + MAX_EC_SIZE];
543 
544         tmp[0..size].copy_from_slice(&self.data[offset..offset + size]);
545         for i in 0..size {
546             let lead_coeff = tmp[i] as usize;
547             if lead_coeff == 0 {
548                 continue;
549             }
550             let log_lead_coeff = usize::from(LOG_TABLE[lead_coeff]);
551             for (u, &v) in tmp[i + 1..].iter_mut().zip(self.poly.iter()) {
552                 *u ^= EXP_TABLE[(usize::from(v) + log_lead_coeff) % 255];
553             }
554         }
555         self.data[ec_offset..ec_offset + self.ec_size]
556             .copy_from_slice(&tmp[size..size + self.ec_size]);
557     }
558 
compute_error_code(&mut self)559     fn compute_error_code(&mut self) {
560         let mut offset = 0;
561         let mut ec_offset = self.g1_blocks * self.g1_blk_size + self.g2_blocks * self.g2_blk_size;
562 
563         for _ in 0..self.g1_blocks {
564             self.error_code_for_blocks(offset, self.g1_blk_size, ec_offset);
565             offset += self.g1_blk_size;
566             ec_offset += self.ec_size;
567         }
568         for _ in 0..self.g2_blocks {
569             self.error_code_for_blocks(offset, self.g2_blk_size, ec_offset);
570             offset += self.g2_blk_size;
571             ec_offset += self.ec_size;
572         }
573     }
574 
encode(&mut self, segments: &[&Segment<'_>])575     fn encode(&mut self, segments: &[&Segment<'_>]) {
576         self.add_segments(segments);
577         self.compute_error_code();
578     }
579 
iter(&self) -> EncodedMsgIterator<'_>580     fn iter(&self) -> EncodedMsgIterator<'_> {
581         EncodedMsgIterator {
582             em: self,
583             offset: 0,
584         }
585     }
586 }
587 
588 /// Iterator, to retrieve the data in the interleaved order needed by QR code.
589 struct EncodedMsgIterator<'a> {
590     em: &'a EncodedMsg<'a>,
591     offset: usize,
592 }
593 
594 impl Iterator for EncodedMsgIterator<'_> {
595     type Item = u8;
596 
597     /// Send the bytes in interleaved mode, first byte of first block of group1,
598     /// then first byte of second block of group1, ...
next(&mut self) -> Option<Self::Item>599     fn next(&mut self) -> Option<Self::Item> {
600         let em = self.em;
601         let blocks = em.g1_blocks + em.g2_blocks;
602         let g1_end = em.g1_blocks * em.g1_blk_size;
603         let g2_end = g1_end + em.g2_blocks * em.g2_blk_size;
604         let ec_end = g2_end + em.ec_size * blocks;
605 
606         if self.offset >= ec_end {
607             return None;
608         }
609 
610         let offset = if self.offset < em.g1_blk_size * blocks {
611             // group1 and group2 interleaved
612             let blk = self.offset % blocks;
613             let blk_off = self.offset / blocks;
614             if blk < em.g1_blocks {
615                 blk * em.g1_blk_size + blk_off
616             } else {
617                 g1_end + em.g2_blk_size * (blk - em.g1_blocks) + blk_off
618             }
619         } else if self.offset < g2_end {
620             // last byte of group2 blocks
621             let blk2 = self.offset - blocks * em.g1_blk_size;
622             em.g1_blk_size * em.g1_blocks + blk2 * em.g2_blk_size + em.g2_blk_size - 1
623         } else {
624             // EC blocks
625             let ec_offset = self.offset - g2_end;
626             let blk = ec_offset % blocks;
627             let blk_off = ec_offset / blocks;
628 
629             g2_end + blk * em.ec_size + blk_off
630         };
631         self.offset += 1;
632         Some(em.data[offset])
633     }
634 }
635 
636 /// A QR code image, encoded as a linear binary framebuffer.
637 /// 1 bit per module (pixel), each new line start at next byte boundary.
638 /// Max width is 177 for V40 QR code, so `u8` is enough for coordinate.
639 struct QrImage<'a> {
640     data: &'a mut [u8],
641     width: u8,
642     stride: u8,
643     version: Version,
644 }
645 
646 impl QrImage<'_> {
new<'a, 'b>(em: &'b EncodedMsg<'b>, qrdata: &'a mut [u8]) -> QrImage<'a>647     fn new<'a, 'b>(em: &'b EncodedMsg<'b>, qrdata: &'a mut [u8]) -> QrImage<'a> {
648         let width = em.version.width();
649         let stride = width.div_ceil(8);
650         let data = qrdata;
651 
652         let mut qr_image = QrImage {
653             data,
654             width,
655             stride,
656             version: em.version,
657         };
658         qr_image.draw_all(em.iter());
659         qr_image
660     }
661 
clear(&mut self)662     fn clear(&mut self) {
663         self.data.fill(0);
664     }
665 
666     /// Set pixel to light color.
set(&mut self, x: u8, y: u8)667     fn set(&mut self, x: u8, y: u8) {
668         let off = y as usize * self.stride as usize + x as usize / 8;
669         let mut v = self.data[off];
670         v |= 0x80 >> (x % 8);
671         self.data[off] = v;
672     }
673 
674     /// Invert a module color.
xor(&mut self, x: u8, y: u8)675     fn xor(&mut self, x: u8, y: u8) {
676         let off = y as usize * self.stride as usize + x as usize / 8;
677         self.data[off] ^= 0x80 >> (x % 8);
678     }
679 
680     /// Draw a light square at (x, y) top left corner.
draw_square(&mut self, x: u8, y: u8, size: u8)681     fn draw_square(&mut self, x: u8, y: u8, size: u8) {
682         for k in 0..size {
683             self.set(x + k, y);
684             self.set(x, y + k + 1);
685             self.set(x + size, y + k);
686             self.set(x + k + 1, y + size);
687         }
688     }
689 
690     // Finder pattern: 3 8x8 square at the corners.
draw_finders(&mut self)691     fn draw_finders(&mut self) {
692         self.draw_square(1, 1, 4);
693         self.draw_square(self.width - 6, 1, 4);
694         self.draw_square(1, self.width - 6, 4);
695         for k in 0..8 {
696             self.set(k, 7);
697             self.set(self.width - k - 1, 7);
698             self.set(k, self.width - 8);
699         }
700         for k in 0..7 {
701             self.set(7, k);
702             self.set(self.width - 8, k);
703             self.set(7, self.width - 1 - k);
704         }
705     }
706 
is_finder(&self, x: u8, y: u8) -> bool707     fn is_finder(&self, x: u8, y: u8) -> bool {
708         let end = self.width - 8;
709         #[expect(clippy::nonminimal_bool)]
710         {
711             (x < 8 && y < 8) || (x < 8 && y >= end) || (x >= end && y < 8)
712         }
713     }
714 
715     // Alignment pattern: 5x5 squares in a grid.
draw_alignments(&mut self)716     fn draw_alignments(&mut self) {
717         let positions = self.version.alignment_pattern();
718         for &x in positions.iter() {
719             for &y in positions.iter() {
720                 if !self.is_finder(x, y) {
721                     self.draw_square(x - 1, y - 1, 2);
722                 }
723             }
724         }
725     }
726 
is_alignment(&self, x: u8, y: u8) -> bool727     fn is_alignment(&self, x: u8, y: u8) -> bool {
728         let positions = self.version.alignment_pattern();
729         for &ax in positions.iter() {
730             for &ay in positions.iter() {
731                 if self.is_finder(ax, ay) {
732                     continue;
733                 }
734                 if x >= ax - 2 && x <= ax + 2 && y >= ay - 2 && y <= ay + 2 {
735                     return true;
736                 }
737             }
738         }
739         false
740     }
741 
742     // Timing pattern: 2 dotted line between the finder patterns.
draw_timing_patterns(&mut self)743     fn draw_timing_patterns(&mut self) {
744         let end = self.width - 8;
745 
746         for x in (9..end).step_by(2) {
747             self.set(x, 6);
748             self.set(6, x);
749         }
750     }
751 
is_timing(&self, x: u8, y: u8) -> bool752     fn is_timing(&self, x: u8, y: u8) -> bool {
753         x == 6 || y == 6
754     }
755 
756     // Mask info: 15 bits around the finders, written twice for redundancy.
draw_maskinfo(&mut self)757     fn draw_maskinfo(&mut self) {
758         let info: u16 = FORMAT_INFOS_QR_L[0];
759         let mut skip = 0;
760 
761         for k in 0..7 {
762             if k == 6 {
763                 skip = 1;
764             }
765             if info & (1 << (14 - k)) == 0 {
766                 self.set(k + skip, 8);
767                 self.set(8, self.width - 1 - k);
768             }
769         }
770         skip = 0;
771         for k in 0..8 {
772             if k == 2 {
773                 skip = 1;
774             }
775             if info & (1 << (7 - k)) == 0 {
776                 self.set(8, 8 - skip - k);
777                 self.set(self.width - 8 + k, 8);
778             }
779         }
780     }
781 
is_maskinfo(&self, x: u8, y: u8) -> bool782     fn is_maskinfo(&self, x: u8, y: u8) -> bool {
783         let end = self.width - 8;
784         // Count the dark module as mask info.
785         (x <= 8 && y == 8) || (y <= 8 && x == 8) || (x == 8 && y >= end) || (x >= end && y == 8)
786     }
787 
788     // Version info: 18bits written twice, close to the finders.
draw_version_info(&mut self)789     fn draw_version_info(&mut self) {
790         let vinfo = self.version.version_info();
791         let pos = self.width - 11;
792 
793         if vinfo != 0 {
794             for x in 0..3 {
795                 for y in 0..6 {
796                     if vinfo & (1 << (x + y * 3)) == 0 {
797                         self.set(x + pos, y);
798                         self.set(y, x + pos);
799                     }
800                 }
801             }
802         }
803     }
804 
is_version_info(&self, x: u8, y: u8) -> bool805     fn is_version_info(&self, x: u8, y: u8) -> bool {
806         let vinfo = self.version.version_info();
807         let pos = self.width - 11;
808 
809         vinfo != 0 && ((x >= pos && x < pos + 3 && y < 6) || (y >= pos && y < pos + 3 && x < 6))
810     }
811 
812     /// Returns true if the module is reserved (Not usable for data and EC).
is_reserved(&self, x: u8, y: u8) -> bool813     fn is_reserved(&self, x: u8, y: u8) -> bool {
814         self.is_alignment(x, y)
815             || self.is_finder(x, y)
816             || self.is_timing(x, y)
817             || self.is_maskinfo(x, y)
818             || self.is_version_info(x, y)
819     }
820 
821     /// Last module to draw, at bottom left corner.
is_last(&self, x: u8, y: u8) -> bool822     fn is_last(&self, x: u8, y: u8) -> bool {
823         x == 0 && y == self.width - 1
824     }
825 
826     /// Move to the next module according to QR code order.
827     ///
828     /// From bottom right corner, to bottom left corner.
next(&self, x: u8, y: u8) -> (u8, u8)829     fn next(&self, x: u8, y: u8) -> (u8, u8) {
830         let x_adj = if x <= 6 { x + 1 } else { x };
831         let column_type = (self.width - x_adj) % 4;
832 
833         match column_type {
834             2 if y > 0 => (x + 1, y - 1),
835             0 if y < self.width - 1 => (x + 1, y + 1),
836             0 | 2 if x == 7 => (x - 2, y),
837             _ => (x - 1, y),
838         }
839     }
840 
841     /// Find next module that can hold data.
next_available(&self, x: u8, y: u8) -> (u8, u8)842     fn next_available(&self, x: u8, y: u8) -> (u8, u8) {
843         let (mut x, mut y) = self.next(x, y);
844         while self.is_reserved(x, y) && !self.is_last(x, y) {
845             (x, y) = self.next(x, y);
846         }
847         (x, y)
848     }
849 
draw_data(&mut self, data: impl Iterator<Item = u8>)850     fn draw_data(&mut self, data: impl Iterator<Item = u8>) {
851         let (mut x, mut y) = (self.width - 1, self.width - 1);
852         for byte in data {
853             for s in 0..8 {
854                 if byte & (0x80 >> s) == 0 {
855                     self.set(x, y);
856                 }
857                 (x, y) = self.next_available(x, y);
858             }
859         }
860         // Set the remaining modules (0, 3 or 7 depending on version).
861         // because 0 correspond to a light module.
862         while !self.is_last(x, y) {
863             if !self.is_reserved(x, y) {
864                 self.set(x, y);
865             }
866             (x, y) = self.next(x, y);
867         }
868     }
869 
870     /// Apply checkerboard mask to all non-reserved modules.
apply_mask(&mut self)871     fn apply_mask(&mut self) {
872         for x in 0..self.width {
873             for y in 0..self.width {
874                 if (x ^ y) % 2 == 0 && !self.is_reserved(x, y) {
875                     self.xor(x, y);
876                 }
877             }
878         }
879     }
880 
881     /// Draw the QR code with the provided data iterator.
draw_all(&mut self, data: impl Iterator<Item = u8>)882     fn draw_all(&mut self, data: impl Iterator<Item = u8>) {
883         // First clear the table, as it may have already some data.
884         self.clear();
885         self.draw_finders();
886         self.draw_alignments();
887         self.draw_timing_patterns();
888         self.draw_version_info();
889         self.draw_data(data);
890         self.draw_maskinfo();
891         self.apply_mask();
892     }
893 }
894 
895 /// C entry point for the rust QR Code generator.
896 ///
897 /// Write the QR code image in the data buffer, and return the QR code width,
898 /// or 0, if the data doesn't fit in a QR code.
899 ///
900 /// * `url`: The base URL of the QR code. It will be encoded as Binary segment.
901 /// * `data`: A pointer to the binary data, to be encoded. if URL is NULL, it
902 ///   will be encoded as binary segment, otherwise it will be encoded
903 ///   efficiently as a numeric segment, and appended to the URL.
904 /// * `data_len`: Length of the data, that needs to be encoded, must be less
905 ///   than `data_size`.
906 /// * `data_size`: Size of data buffer, it should be at least 4071 bytes to hold
907 ///   a V40 QR code. It will then be overwritten with the QR code image.
908 /// * `tmp`: A temporary buffer that the QR code encoder will use, to write the
909 ///   segments and ECC.
910 /// * `tmp_size`: Size of the temporary buffer, it must be at least 3706 bytes
911 ///   long for V40.
912 ///
913 /// # Safety
914 ///
915 /// * `url` must be null or point at a nul-terminated string.
916 /// * `data` must be valid for reading and writing for `data_size` bytes.
917 /// * `tmp` must be valid for reading and writing for `tmp_size` bytes.
918 ///
919 /// They must remain valid for the duration of the function call.
920 #[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, ) -> u8921 pub unsafe extern "C" fn drm_panic_qr_generate(
922     url: *const kernel::ffi::c_char,
923     data: *mut u8,
924     data_len: usize,
925     data_size: usize,
926     tmp: *mut u8,
927     tmp_size: usize,
928 ) -> u8 {
929     if data_size < 4071 || tmp_size < 3706 || data_len > data_size {
930         return 0;
931     }
932     // SAFETY: The caller ensures that `data` is a valid pointer for reading and
933     // writing `data_size` bytes.
934     let data_slice: &mut [u8] = unsafe { core::slice::from_raw_parts_mut(data, data_size) };
935     // SAFETY: The caller ensures that `tmp` is a valid pointer for reading and
936     // writing `tmp_size` bytes.
937     let tmp_slice: &mut [u8] = unsafe { core::slice::from_raw_parts_mut(tmp, tmp_size) };
938     if url.is_null() {
939         match EncodedMsg::new(&[&Segment::Binary(&data_slice[0..data_len])], tmp_slice) {
940             None => 0,
941             Some(em) => {
942                 let qr_image = QrImage::new(&em, data_slice);
943                 qr_image.width
944             }
945         }
946     } else {
947         // SAFETY: The caller ensures that `url` is a valid pointer to a
948         // nul-terminated string.
949         let url_cstr: &CStr = unsafe { CStr::from_char_ptr(url) };
950         let segments = &[
951             &Segment::Binary(url_cstr.as_bytes()),
952             &Segment::Numeric(&data_slice[0..data_len]),
953         ];
954         match EncodedMsg::new(segments, tmp_slice) {
955             None => 0,
956             Some(em) => {
957                 let qr_image = QrImage::new(&em, data_slice);
958                 qr_image.width
959             }
960         }
961     }
962 }
963 
964 /// Returns the maximum data size that can fit in a QR code of this version.
965 /// * `version`: QR code version, between 1-40.
966 /// * `url_len`: Length of the URL.
967 ///
968 /// * If `url_len` > 0, remove the 2 segments header/length and also count the
969 ///   conversion to numeric segments.
970 /// * If `url_len` = 0, only removes 3 bytes for 1 binary segment.
971 ///
972 /// # Safety
973 ///
974 /// Always safe to call.
975 // Required to be unsafe due to the `#[export]` annotation.
976 #[export]
drm_panic_qr_max_data_size(version: u8, url_len: usize) -> usize977 pub unsafe extern "C" fn drm_panic_qr_max_data_size(version: u8, url_len: usize) -> usize {
978     #[expect(clippy::manual_range_contains)]
979     if version < 1 || version > 40 {
980         return 0;
981     }
982     let max_data = Version(version as usize).max_data();
983 
984     if url_len > 0 {
985         // Binary segment (URL) 4 + 16 bits, numeric segment (kmsg) 4 + 12 bits => 5 bytes.
986         if url_len + 5 >= max_data {
987             0
988         } else {
989             let max = max_data - url_len - 5;
990             (max * 39) / 40
991         }
992     } else {
993         // Remove 3 bytes for the binary segment (header 4 bits, length 16 bits, stop 4bits).
994         max_data - 3
995     }
996 }
997