<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="/assets/xslt/atom.xslt" ?>
<?xml-stylesheet type="text/css" href="/assets/css/atom.css" ?>
<feed xmlns="http://www.w3.org/2005/Atom">
	<id>https://knzl.at/</id>
	<title>KNZL: Seb Kienzl&#39;s page</title>
	<updated>2026-05-18T22:32:32+00:00</updated>

	<subtitle>Software engineering blog, updated daily</subtitle>

	
		
		<author>
			
				<name>seb</name>
			
			
			
		</author>
	

	<link href="https://knzl.at/atom.xml" rel="self" type="application/rss+xml" />
	<link href="https://knzl.at/" rel="alternate" type="text/html" />

	<generator uri="http://jekyllrb.com" version="2.5.3">Jekyll</generator>

	
		<entry>
			<id>https://knzl.at/stm32f4xx_fmc_bugs/</id>
			<title>SDRAM problems with STM32F427/437/429/439</title>
			<link href="https://knzl.at/stm32f4xx_fmc_bugs/" rel="alternate" type="text/html" title="SDRAM problems with STM32F427/437/429/439" />
			<updated>2017-12-13T00:00:00+00:00</updated>

			
				
				<author>
					
						<name>seb</name>
					
					
					
				</author>
			
			<summary></summary>
			<content type="html" xml:base="https://knzl.at/stm32f4xx_fmc_bugs/">&lt;p&gt;The FMC (flexible memory controller) of these microcontrollers is a bug ridden beast. The latest errata sheet lists a total of 15 “silicon limitations”.
Two of them are connected to SDRAM and are particularily ugly, as they may result in corrupt reads.
As of now (Dec 2017), both of them are not fixed in any revision,
so you may want to continue reading if you use any of these types with SDRAM…&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;a-mysterious-bug&quot;&gt;A mysterious bug…&lt;/h2&gt;

&lt;p&gt;The last few days, my client and I were hunting a mysterious bug: When the STM32F439 was really busy (i.e. lots of interrupts),
very, &lt;em&gt;very&lt;/em&gt; seldomly two invalid bytes would arrive at the host over USB.&lt;/p&gt;

&lt;p&gt;After putting checks in place and making sure the data gets handed to the USB-stack correctly, it turned out that when the
bug occured, the invalid data was actually read from the SDRAM, although the same data seemed ok there.&lt;/p&gt;

&lt;p&gt;After re-checking that the SDRAM timing and initialization was correct, studying the latest &lt;a href=&quot;http://www.st.com/content/ccc/resource/technical/document/errata_sheet/38/e6/37/64/08/38/45/67/DM00068628.pdf/files/DM00068628.pdf/jcr:content/translations/en.DM00068628.pdf&quot;&gt;errata sheet&lt;/a&gt;
revealed a likely candidate: “2.11.15 SDRAM bank address corruption upon an interruption of CPU read burst access”.&lt;/p&gt;

&lt;p&gt;If the CPU gets an interrupt while it is busy with an &lt;code&gt;LDM&lt;/code&gt; from SDRAM, the next read from another bank of the SDRAM may result in wrong data read.
Öha.&lt;/p&gt;

&lt;h2 id=&quot;who-should-be-concerned&quot;&gt;Who should be concerned?&lt;/h2&gt;

&lt;p&gt;Everyone that uses a STM32F427/STM32F437/STM32F429/STM32F439 with SDRAM.
Here, the problem went unnoticed for a couple of years, although these microcontrollers have been used in numerous projects.
Only in one project under very specific circumstances the problem surfaced.&lt;/p&gt;

&lt;h2 id=&quot;the-workarounds&quot;&gt;The workarounds&lt;/h2&gt;

&lt;p&gt;Luckily, there are several workarounds for every taste.&lt;/p&gt;

&lt;h3 id=&quot;workaround-1-32-bit-sdram&quot;&gt;Workaround #1: 32-bit SDRAM&lt;/h3&gt;

&lt;p&gt;If you’re using 32-bit SDRAM, you could simply disable the SDRAM’s FIFO by clearing RBURST in FMC_SDCR1/FMC_SDCR2 when initialzing the FMC.&lt;/p&gt;

&lt;p&gt;Why only 32-bit SDRAM? Because there’s another bug in the FMC: “2.11.5 Interruption of CPU read burst access to an end of SDRAM row”
that only affects 8- and 16-bit SDRAMs. The workaround for this problem would be turning the FIFO on,
which is the opposite of the workaround for the problem we’re trying to solve.&lt;/p&gt;

&lt;p&gt;But anyway, turning off the FIFO is a viable workaround when using 32-bit SDRAMs.
It will probably hurt SDRAM-performance a little, but maybe that’s not an issue in your case.&lt;/p&gt;

&lt;h3 id=&quot;workaround-2-set-dismcycint&quot;&gt;Workaround #2: Set DISMCYCINT&lt;/h3&gt;

&lt;p&gt;Another workaround I came up with that’s not mentioned in the errata sheet is to set DISMCYCINT in the “Auxiliary control register” (ACTLR).
If this bit is set, LDMs will not get interrupted and the problem will go away.&lt;/p&gt;

&lt;p&gt;There’s a drawback, though: The worst-case interrupt latency increases.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka16487.html&quot;&gt;This FAQ entry&lt;/a&gt; tells us that the longest possible
burst is a &lt;code&gt;VLDM Rx, [S0-S31]&lt;/code&gt;, which is 32 words or 128 bytes.&lt;/p&gt;

&lt;p&gt;In our configuration (16-bit SDRAM @ 90 MHz), such a burst takes almost 1 µs. This may be too long if you have really hard realtime requirements.
Other than that, it’s a very simple and effective workaround.&lt;/p&gt;

&lt;h3 id=&quot;workaround-3-precharge-all-before-the-2nd-read&quot;&gt;Workaround #3: “Precharge all” before the 2nd read&lt;/h3&gt;

&lt;p&gt;Another workaround mentioned in the errata sheet is to “[…] send a PRECHARGE ALL command before the second read access […]”.&lt;/p&gt;

&lt;p&gt;As &lt;em&gt;before&lt;/em&gt; the second read access is &lt;em&gt;after&lt;/em&gt; the first (interrupted) access, we could send a “precharge all” command first thing in every ISR.&lt;/p&gt;

&lt;p&gt;To achieve that, one can wrap all ISRs with a specially crafted vector table.&lt;/p&gt;

&lt;p&gt;A few things to consider:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;VTOR must point to this table.&lt;/li&gt;
  &lt;li&gt;Any vector-table must be aligned to 128 words (512 bytes).&lt;/li&gt;
  &lt;li&gt;To be on the safe side, make sure the first two entries (initial SP and initial PC) contain proper values. There may be some code using them for a reset.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, have all interrupt-vectors point to a routine something like that:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-nasm&quot; data-lang=&quot;nasm&quot;&gt;&lt;span class=&quot;n&quot;&gt;isr_wrapper&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;; send PRECHARGE ALL command to SDRAM 1 via FMC&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;LDR&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;R0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0xa0000150&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;; FMC_SDCMR register&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;MOVS&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;R1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mh&quot;&gt;0x12&lt;/span&gt;       &lt;span class=&quot;c&quot;&gt;; Send PALL to SDRAM 1&lt;/span&gt;
	&lt;span class=&quot;k&quot;&gt;STR&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;R1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[R0]&lt;/span&gt;
	
	&lt;span class=&quot;n&quot;&gt;MRS&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;R0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IPSR&lt;/span&gt;        &lt;span class=&quot;c&quot;&gt;; Get current interrupt number ..&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;; .. and use it as the index to look up the actual ISR and branch there&lt;/span&gt;
	&lt;span class=&quot;c&quot;&gt;; (in our case, we are using a vector table in RAM)&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;LDR&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;R1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__VECTOR_RAM&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;LDR&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;R0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;R1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;R0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;LSL&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;]&lt;/span&gt;
	&lt;span class=&quot;n&quot;&gt;BX&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;R0&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you have two SDRAMs, you’ll have to send &lt;em&gt;PALL&lt;/em&gt; to both of them.
Also, your actual vector table is probably called differently, or it may just sit at address 0 if you’re
using the vector table in Flash ROM.&lt;/p&gt;

&lt;p&gt;This is the workaround we finally went with as it hardly increases interrupt latency and is not too invasive.
Long-term testing showed that with this in place, the problem doesn’t occur any more.&lt;/p&gt;
</content>

			
				<category term="code" />
			
				<category term="embedded" />
			
			
				<category term="stm32" />
			

			<published>2017-12-13T00:00:00+00:00</published>
		</entry>
	
		<entry>
			<id>https://knzl.at/systemd-removeipc/</id>
			<title>systemd-logind deletes your message queues (RemoveIPC)</title>
			<link href="https://knzl.at/systemd-removeipc/" rel="alternate" type="text/html" title="systemd-logind deletes your message queues (RemoveIPC)" />
			<updated>2017-08-05T00:00:00+00:00</updated>

			
				
				<author>
					
						<name>seb</name>
					
					
					
				</author>
			
			<summary></summary>
			<content type="html" xml:base="https://knzl.at/systemd-removeipc/">&lt;p&gt;When something unexpected happens in a GNU/Linux system nowadays, it’s likely that systemd is involved somehow.
If you want yet another spectacular example of how systemd and especially its author know what’s best for everyone, read on…&lt;/p&gt;

&lt;!--more--&gt;

&lt;p&gt;I wrote software for GNU/Linux where two processes communicate through a POSIX message queue (see &lt;code&gt;man mq_overview&lt;/code&gt; or &lt;code&gt;man mq_open&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;So far so good, except that the message queue kept on disappearing after a while for no appearant reason.&lt;/p&gt;

&lt;p&gt;I found that systemd mounts the mqueue-pseudo-filesystem at &lt;code&gt;/dev/mqueue&lt;/code&gt;, which contains all message queues.
It seemed quite likely that the queue was repeatedly being deleted from there.&lt;/p&gt;

&lt;p&gt;A quickly written &lt;a href=&quot;http://www-users.cs.umn.edu/~boutcher/kprobes/&quot;&gt;jprobe&lt;/a&gt; on &lt;code&gt;mqueue_unlink&lt;/code&gt; revealed the culprit: systemd-logind.&lt;/p&gt;

&lt;p&gt;Once again my gut-feeling that systemd is involved was right. Now if you (like I did) think this is a bug: It isn’t.&lt;/p&gt;

&lt;p&gt;After reading the source and finding out that it’s actually default behaviour (see &lt;a href=&quot;https://vendor2.nginfotpdx.net/gitlab/upstream/systemd/commit/66cdd0f2d0670b054bd27dad16fcb5838b11dde3&quot;&gt;this commit&lt;/a&gt;)
to remove “POSIX IPC Objects” when a user “fully logs out” (see bottom of &lt;code&gt;man logind.conf&lt;/code&gt;) I wasn’t very surprised about You-Know-Who telling us &lt;a href=&quot;https://github.com/systemd/systemd/issues/2039&quot;&gt;that it’s the right thing to do &lt;em&gt;by default&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;My advise: Put &lt;code&gt;RemoveIPC=no&lt;/code&gt; into your &lt;code&gt;/etc/systemd/logind.conf&lt;/code&gt; or
better &lt;a href=&quot;http://without-systemd.org&quot;&gt;avoid systemd&lt;/a&gt; altogether if you can.
&lt;a href=&quot;http://suckless.org/sucks/systemd&quot;&gt;Here&lt;/a&gt;’s a collection of more
systemd-crazyness.&lt;/p&gt;
</content>

			
				<category term="code" />
			
				<category term="administration" />
			
			
				<category term="linux" />
			
				<category term="systemd" />
			

			<published>2017-08-05T00:00:00+00:00</published>
		</entry>
	
		<entry>
			<id>https://knzl.at/adplug-macsopera/</id>
			<title>SoundFX Macs Opera support for AdPlug</title>
			<link href="https://knzl.at/adplug-macsopera/" rel="alternate" type="text/html" title="SoundFX Macs Opera support for AdPlug" />
			<updated>2017-01-13T00:00:00+00:00</updated>

			
				
				<author>
					
						<name>seb</name>
					
					
					
				</author>
			
			<summary></summary>
			<content type="html" xml:base="https://knzl.at/adplug-macsopera/">&lt;p&gt;Many of you remember the FM-sounds that the OPL-chips on old soundcards like the AdLib or the Sound Blaster make.
One cold day last December, I remembered that when I was around 12 years old, I bought tracker-software for creating AdLib-tunes.
More important things had to wait, I had an “open invoice” with that specific piece of software…&lt;/p&gt;

&lt;!--more--&gt;

&lt;p&gt;It was boxed software on one 5¼” disk and I bought it because the box promised
that with that software, I’d be able to add music to my own programs!&lt;/p&gt;

&lt;p&gt;Being an avid QuickBASIC programmer (and electric guitar player) at that age, I was hooked.
However, my enthusiasm waned off when I read the documentation on the TSR that came with it:
Allocating memory? Calling an interrupt? What?&lt;/p&gt;

&lt;p&gt;None of my computer-friends could tell me how this works.
Since this was one of the few softwares that I actually bought back then, I was disappointed.&lt;/p&gt;

&lt;p&gt;Some 25 years later I didn’t remember the name of the software any more, but after some looking around I stumbled over YouTube videos by a Mr. Grzondziel that showed the tracker.
Thanks for sending me the software! Oddly enough, I was in contact with him a few years before that about some other topic.&lt;/p&gt;

&lt;p&gt;Also, I noticed that AdPlug, an open source AdLib player, didn’t have support for files composed with this tracker.&lt;/p&gt;

&lt;p&gt;I couldn’t find the original author, so after some reverse engineering
(and running Turbo Debugger through a virtual serial port on two DOSBoxes)
and lots of listening, here goes: &lt;a href=&quot;https://github.com/adplug/adplug/commit/0c9e68a9c95bfb1b419c1952b1d442f7c7b2ab80&quot;&gt;SoundFX Macs Opera support for AdPlug&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And this is how it sounds, this song is “Necronom” by &lt;a href=&quot;https://www.mobygames.com/developer/sheet/view/developerId,49951/&quot;&gt;Michael Tschögl&lt;/a&gt;:&lt;/p&gt;

&lt;audio controls=&quot;&quot;&gt;&lt;source src=&quot;necronom.mp3&quot; type=&quot;audio/mpeg&quot; /&gt;&lt;/audio&gt;
</content>

			
				<category term="code" />
			
			
				<category term="nostalgia" />
			

			<published>2017-01-13T00:00:00+00:00</published>
		</entry>
	
		<entry>
			<id>https://knzl.at/cmake-exclude-from-all/</id>
			<title>CMake: EXCLUDE_FROM_ALL vs. EXCLUDE_FROM_DEFAULT_BUILD</title>
			<link href="https://knzl.at/cmake-exclude-from-all/" rel="alternate" type="text/html" title="CMake: EXCLUDE_FROM_ALL vs. EXCLUDE_FROM_DEFAULT_BUILD" />
			<updated>2016-11-02T00:00:00+00:00</updated>

			
				
				<author>
					
						<name>seb</name>
					
					
					
				</author>
			
			<summary>Getting EXCLUDE_FROM_ALL behaviour in Visual Studio</summary>
			<content type="html" xml:base="https://knzl.at/cmake-exclude-from-all/">&lt;p&gt;&lt;code&gt;add_library(target EXCLUDE_FROM_ALL ...)&lt;/code&gt; is really convenient with Make-generators if you want to define libraries that should only be built if another target depends on them. This currently doesn’t work (well) for Visual Studio generators, but here’s a trick how to get this behaviour in Visual Studio as well…&lt;/p&gt;

&lt;!--more--&gt;

&lt;p&gt;(Written for CMake 3.6)&lt;/p&gt;

&lt;h2 id=&quot;excludefromall&quot;&gt;EXCLUDE_FROM_ALL&lt;/h2&gt;

&lt;p&gt;As written in the &lt;a href=&quot;https://cmake.org/cmake/help/v3.6/prop_tgt/EXCLUDE_FROM_ALL.html&quot;&gt;CMake docs&lt;/a&gt;, the &lt;code&gt;EXCLUDE_FROM_ALL&lt;/code&gt; target-property causes a target to be excluded from the “all” build-target, which is the default if &lt;code&gt;make&lt;/code&gt; is started without any args.&lt;/p&gt;

&lt;p&gt;If used for static libraries (e.g. by using &lt;code&gt;add_library(target EXCLUDE_FROM_ALL ...)&lt;/code&gt;), the library will be built nevertheless if another target (library or executable) depends on it.&lt;/p&gt;

&lt;p&gt;Like this, you can define a bunch of libraries (e.g. in your shared codebase) and only those that are actually needed will be built.&lt;/p&gt;

&lt;p&gt;This reduces build times and makes it easier to handle component-dependencies.&lt;/p&gt;

&lt;p&gt;I’m not sure if this use case is what the implementor of &lt;code&gt;EXCLUDE_FROM_ALL&lt;/code&gt; had in mind, but I find it practical like that.&lt;/p&gt;

&lt;h2 id=&quot;excludefromdefaultbuild&quot;&gt;EXCLUDE_FROM_DEFAULT_BUILD&lt;/h2&gt;

&lt;p&gt;Interestingly, there’s the &lt;a href=&quot;https://cmake.org/cmake/help/v3.6/prop_tgt/EXCLUDE_FROM_DEFAULT_BUILD.html&quot;&gt;EXCLUDE_FROM_DEFAULT_BUILD&lt;/a&gt; target property which on first sight seems to be somewhat redundant.&lt;/p&gt;

&lt;p&gt;But it isn’t, it’s a property specific to the Visual Studio generator and only says that a target (i.e. a Visual Studio project) isn’t built when the Solution is build by pressing “Build Solution (F7)”.&lt;/p&gt;

&lt;p&gt;The difference to &lt;code&gt;EXCLUDE_FROM_ALL&lt;/code&gt;: If a target is excluded from build like that, it won’t be built even if another target depends on it.&lt;/p&gt;

&lt;p&gt;This doesn’t mean that &lt;code&gt;EXCLUDE_FROM_ALL&lt;/code&gt; is ineffective with Visual Studio: If you build the “ALL_BUILD” project, you’ll get the same behaviour as with Make.&lt;/p&gt;

&lt;p&gt;While this works, I don’t like it: People are used to hitting F7 (or whatever the shortcut is) and the project should build.&lt;/p&gt;

&lt;h2 id=&quot;the-solution&quot;&gt;The solution&lt;/h2&gt;

&lt;p&gt;My use case:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A bunch of static libraries in the shared codebase where not every library is needed in every project&lt;/li&gt;
  &lt;li&gt;A (CMake-) project consists of one or more executables&lt;/li&gt;
  &lt;li&gt;Builds with Visual Studio and Make&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Others seem to have wanted to do the same:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://gitlab.kitware.com/cmake/cmake/issues/12379&quot;&gt;https://gitlab.kitware.com/cmake/cmake/issues/12379&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://public.kitware.com/pipermail/cmake/2011-August/045662.html&quot;&gt;http://public.kitware.com/pipermail/cmake/2011-August/045662.html&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://public.kitware.com/pipermail/cmake/2013-February/053528.html&quot;&gt;http://public.kitware.com/pipermail/cmake/2013-February/053528.html&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is my solution for this problem:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-cmake&quot; data-lang=&quot;cmake&quot;&gt;&lt;span class=&quot;c1&quot;&gt;# Override add_library() and set the &quot;EXCLUDE_FROM_DEFAULT_BUILD&quot; property to TRUE on all libraries that use &quot;EXCLUDE_FROM_ALL&quot;.&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;add_library TARGET&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;nf&quot;&gt;_add_library&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TARGET&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ARGN&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;nf&quot;&gt;cmake_parse_arguments&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;OPTS &lt;span class=&quot;s2&quot;&gt;&quot;EXCLUDE_FROM_ALL&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ARGN&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;nb&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;OPTS_EXCLUDE_FROM_ALL&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;nb&quot;&gt;set_target_properties&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TARGET&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt; PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD TRUE&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;nb&quot;&gt;endif&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;endfunction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Helper function to recursively set EXCLUDE_FROM_DEFAULT_BUILD to FALSE on all targets &quot;TARGET&quot; depends on&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;_include_in_build TARGET&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;nb&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;TARGET &lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TARGET&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;nb&quot;&gt;get_target_property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;TYPE &lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TARGET&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt; TYPE&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;nb&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;TYPE MATCHES &lt;span class=&quot;s2&quot;&gt;&quot;INTERFACE&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;nb&quot;&gt;get_target_property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;DEPS &lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TARGET&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt; INTERFACE_LINK_LIBRARIES&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;nb&quot;&gt;else&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
			&lt;span class=&quot;nb&quot;&gt;set_target_properties&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TARGET&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt; PROPERTIES EXCLUDE_FROM_DEFAULT_BUILD FALSE&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;nb&quot;&gt;get_target_property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;DEPS &lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TARGET&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt; LINK_LIBRARIES&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;nb&quot;&gt;endif&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
		&lt;span class=&quot;nb&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;DEPS&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;nb&quot;&gt;foreach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;D &lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;DEPS&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
				&lt;span class=&quot;nf&quot;&gt;_include_in_build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;D&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
			&lt;span class=&quot;nb&quot;&gt;endforeach&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
		&lt;span class=&quot;nb&quot;&gt;endif&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
	&lt;span class=&quot;nb&quot;&gt;endif&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;endfunction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Take executables as roots to run _include_in_build() on&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;target_link_libraries TARGET&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;nf&quot;&gt;_target_link_libraries&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TARGET&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;ARGN&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	
	&lt;span class=&quot;nb&quot;&gt;get_target_property&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;_TYPE &lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TARGET&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt; TYPE&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;nb&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;_TYPE MATCHES &lt;span class=&quot;s2&quot;&gt;&quot;EXECUTABLE&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
		&lt;span class=&quot;nf&quot;&gt;_include_in_build&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;TARGET&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
	&lt;span class=&quot;nb&quot;&gt;endif&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;endfunction&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;How does it work?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;First, a trick I like to use: Functions like &lt;code&gt;add_library&lt;/code&gt; and &lt;code&gt;target_link_libraries&lt;/code&gt; can be “overridden” by just defining a new version. The original function is still available as e.g. &lt;code&gt;_add_library&lt;/code&gt; or &lt;code&gt;_target_link_libraries&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;For every library that is defined which has the &lt;code&gt;EXCLUDE_FROM_ALL&lt;/code&gt; property set the &lt;code&gt;EXCLUDE_FROM_DEFAULT_BUILD&lt;/code&gt; property is set as well.&lt;/li&gt;
  &lt;li&gt;For every executable target on which &lt;code&gt;target_link_libraries()&lt;/code&gt; is used, the function &lt;code&gt;_include_in_build()&lt;/code&gt; recursively sets &lt;code&gt;EXCLUDE_FROM_DEFAULT_BUILD&lt;/code&gt; to &lt;code&gt;FALSE&lt;/code&gt; on all targets the executable depends on. Imagine the executable as the root of a tree of dependencies which is traversed.&lt;/li&gt;
  &lt;li&gt;There’s special handling for “interface targets”, as they don’t have the &lt;code&gt;EXCLUDE_FROM_DEFAULT_BUILD&lt;/code&gt; property.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h1&gt;

&lt;p&gt;While this works for my use case, I think a better way would be to have the ability to define “non-standalone” targets in CMake. Targets like this would not be built if no other target depends on them. Something to be discussed with the CMake devs…&lt;/p&gt;

&lt;p&gt;That’s all, thanks for reading!&lt;/p&gt;
</content>

			
				<category term="code" />
			
			
				<category term="cmake" />
			

			<published>2016-11-02T00:00:00+00:00</published>
		</entry>
	
		<entry>
			<id>https://knzl.at/debugging-iar-elfs-with-gdb/</id>
			<title>Debugging IAR ELFs with GDB on the STM32F4xx</title>
			<link href="https://knzl.at/debugging-iar-elfs-with-gdb/" rel="alternate" type="text/html" title="Debugging IAR ELFs with GDB on the STM32F4xx" />
			<updated>2016-09-14T00:00:00+00:00</updated>

			
				
				<author>
					
						<name>seb</name>
					
					
					
				</author>
			
			<summary>With C-SPY it works, with GDB it doesn&#39;t?</summary>
			<content type="html" xml:base="https://knzl.at/debugging-iar-elfs-with-gdb/">&lt;p&gt;There are situations where you may not want to use IAR’s C-SPY for debugging but rather would go with GDB.&lt;/p&gt;

&lt;p&gt;So you tell yourself “an ELF is an ELF”, start up J-Link GDB server, attach GDB to it, load the ELF, &lt;code&gt;continue&lt;/code&gt; and… nothing.&lt;/p&gt;

&lt;p&gt;There are several things that can go wrong, read on to find out which…&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;why-use-gdb-instead-of-c-spy&quot;&gt;Why use GDB instead of C-SPY?&lt;/h2&gt;

&lt;p&gt;My client uses IAR’s toolchain.&lt;/p&gt;

&lt;p&gt;However, C-SPY currently (Sep 2016) has one major flaw: It takes &lt;em&gt;forever&lt;/em&gt; to load big ELF files.
Support told us they’ll improve it. GDB loads it instantly.&lt;/p&gt;

&lt;p&gt;Also, you may want to run the ELF through a debugger in environments where you don’t have an IAR license.&lt;/p&gt;

&lt;p&gt;My setup: Segger J-Link, J-Link GDB Server and gdb from the &lt;a href=&quot;https://launchpad.net/gcc-arm-embedded&quot;&gt;GNU ARM Embedded Toolchain&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;What’s the problem, then? Maybe it’s one of the following reasons.&lt;/p&gt;

&lt;h2 id=&quot;reason-1-program-entry-position&quot;&gt;Reason #1: Program entry position&lt;/h2&gt;

&lt;p&gt;GDB honours the “Program entry position” from the ELF header and sets the program counter (PC) accordingly on &lt;code&gt;load&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In my case the IAR linker sets the program entry position to the address of &lt;code&gt;__iar_program_start&lt;/code&gt;.
It is an entry position, sort of, but really it isn’t. Rather, it should be something like the address of &lt;code&gt;Reset_Handler&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Except the PC, also the initial stack pointer (SP) may be bogus.&lt;/p&gt;

&lt;p&gt;To understand what PC/SP really should be, this is what happens when an STM32F4xx starts:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Set SP to the word stored at VTOR+0&lt;/li&gt;
  &lt;li&gt;Set PC to the word stored at VTOR+4&lt;/li&gt;
  &lt;li&gt;Start&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What’s VTOR? It’s the “Vector table offset register”. After reset, it’s 0.&lt;/p&gt;

&lt;p&gt;Is there any memory at 0x00000000? Yes there is, for usual configurations (i.e. boot from flash), the flash memory is aliased to address 0x00000000.&lt;/p&gt;

&lt;p&gt;So, to get the proper values for PC/SP, I’ve found that resetting the CPU after the ELF has been loaded works well.&lt;/p&gt;

&lt;p&gt;To illustrate this, look at this GDB session output:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;C:\Users\seb\...&amp;gt;arm-none-eabi-gdb.exe test.elf
GNU gdb (GNU Tools for ARM Embedded Processors) 7.10.1.20160210-cvs
...
Reading symbols from test.elf...done.
(gdb) target remote localhost:2331
Remote debugging using localhost:2331
0x08000e20 in ?? ()
(gdb) monitor reset
Resetting target
(gdb) load
Loading section A1 rw, size 0x410 lma 0x8000000
Loading section P2 rw, size 0x3c lma 0x8000410
Loading section P3 ro, size 0x1059f8 lma 0x800044c
Start address 0x8043ec8, load size 1072708
Transfer rate: 33792 KB/sec, 4063 bytes/write.
(gdb) stepi
0x08043eca in __iar_program_start ()
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That’s not the right start address, it should be:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(gdb) x/x 0x00000004
0x4:    0x08000fd1
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After a reset, it will fetch the correct PC:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;(gdb) monitor reset
Resetting target
(gdb) stepi
0x08000fd2 in ?? ()
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then, you can just continue the program.&lt;/p&gt;

&lt;p&gt;So something like the following in your &lt;code&gt;gdbinit&lt;/code&gt; should work:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# Connect to GDB Server
target remote localhost:2331

# Reset CPU
monitor reset

# Load ELF
load

# Reset again
monitor reset
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;reason-2-boot-loader-configuration&quot;&gt;Reason #2: Boot loader configuration&lt;/h2&gt;

&lt;p&gt;Now, it still may not work. For example, we use a boot loader configuration: Our boot loader sits in the first 256k of the flash
and the actual application comes after these 256k. The application has its own vector table at 0x08040000.&lt;/p&gt;

&lt;p&gt;Still, for some magical reason, C-SPY is perfectly fine loading and running this application and it uses the proper PC and SP from
the vector table at 0x08040000. How does it do that?&lt;/p&gt;

&lt;p&gt;I stumbled over a comment in &lt;code&gt;startup_stm32f429_439xx.s&lt;/code&gt;:&lt;/p&gt;

&lt;blockquote&gt;
	The name &quot;__vector_table&quot; has special meaning for C-SPY:
	it is where the SP start value is found, and the NVIC vector
	table register (VTOR) is initialized to this address if != 0.
&lt;/blockquote&gt;

&lt;p&gt;So this is what C-SPY does:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Set VTOR to the address of the symbol &lt;code&gt;__vector_table&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;Fetch and set SP and PC from there&lt;/li&gt;
  &lt;li&gt;Run&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of course GDB doesn’t know about this, that’s why it has to be done manually:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# Adjust VTOR (Vector table offset register)
set {int}0xE000ED08 = __vector_table
# Set SP/PC to the values from the actual vector table
set $sp = *(int*)__vector_table
set $pc = *((int*)__vector_table+1)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;0xE000ED08&lt;/code&gt; is the address of the VTOR on the STM32F439 we’re using. I haven’t checked, but it’s probably the same for other controllers of this family.&lt;/p&gt;

&lt;p&gt;That’s all, thanks for reading!&lt;/p&gt;
</content>

			
				<category term="code" />
			
				<category term="embedded" />
			
			
				<category term="embedded" />
			
				<category term="arm" />
			

			<published>2016-09-14T00:00:00+00:00</published>
		</entry>
	
		<entry>
			<id>https://knzl.at/speeding-up-dhcp/</id>
			<title>Speeding up DHCP on bad WiFi links</title>
			<link href="https://knzl.at/speeding-up-dhcp/" rel="alternate" type="text/html" title="Speeding up DHCP on bad WiFi links" />
			<updated>2016-06-05T00:00:00+00:00</updated>

			
				
				<author>
					
						<name>seb</name>
					
					
					
				</author>
			
			<summary>On bad WiFi links, initial DHCP negotiations may take a long time due to lost DHCP responses.</summary>
			<content type="html" xml:base="https://knzl.at/speeding-up-dhcp/">&lt;p&gt;In my current project I noticed that on bad WiFi links initial DHCP negotiations may take a really long time.&lt;/p&gt;

&lt;p&gt;The reason is simple: In the initial steps, DHCP uses UDP broadcast packages that may get lost.&lt;/p&gt;

&lt;p&gt;To find out more and learn how to speed things up, read on …&lt;/p&gt;

&lt;!--more--&gt;

&lt;h2 id=&quot;a-short-80211-primer&quot;&gt;A short 802.11 primer&lt;/h2&gt;

&lt;p&gt;In embedded devices that use WiFi modules that only have egyptian PCB traces as antennas, the packet loss
between the access point (AP) and the WiFi client (STA(tion) in 802.11 terminology) can be high.
When receiving, I could provoke &amp;gt;50% lost packets using modules from different vendors with APs that would receive much better with a proper antenna.
Also, the embedded device may operate in a noisy (RF wise) environment.&lt;/p&gt;

&lt;p&gt;Two facts about 802.11 WLANs which I didn’t know before:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Packets are normally sent through the AP, event if two STAs in the same network (BSS) communicate with each other. There is (T)DLS “Direct Link Setup” in 802.11e/z, but it’s not relevant in this case.&lt;/li&gt;
  &lt;li&gt;MAC unicast packets (i.e. AP-&amp;gt;STA or STA-&amp;gt;AP) are ACK’d and are retransmitted a couple of times as needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By “MAC unicast” I mean that they’re unicast on the data link layer (2), i.e. the packets contain a destination MAC address of a specific device.&lt;/p&gt;

&lt;p&gt;There are also “MAC broadcast” packets, which are only sent by the AP. These packets are not ACK’d. It wouldn’t make much sense to wait for all STAs to ACK a broadcast packet.&lt;/p&gt;

&lt;p&gt;How does this play together with IP?&lt;/p&gt;

&lt;table&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt; &lt;/td&gt;
      &lt;td&gt;IP unicast&lt;/td&gt;
      &lt;td&gt;IP broadcast&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;STA-&amp;gt;AP&lt;/td&gt;
      &lt;td&gt;MAC unicast&lt;/td&gt;
      &lt;td&gt;MAC unicast&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;AP-&amp;gt;STA(s)&lt;/td&gt;
      &lt;td&gt;MAC unicast&lt;/td&gt;
      &lt;td&gt;&lt;strong&gt;MAC broadcast&lt;/strong&gt;&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;As you can see, IP broadcast packets from AP-&amp;gt;STAtions are sent as MAC broadcast, which are not ACK’d and thus are more likely to get lost.&lt;/p&gt;

&lt;p&gt;And this is exactly the problem.&lt;/p&gt;

&lt;p&gt;(Side note: To measure packet loss, send UDP broadcast packets from Ethernet-&amp;gt;AP-&amp;gt;STA and count how many are lost.)&lt;/p&gt;

&lt;h2 id=&quot;a-short-dhcp-primer&quot;&gt;A short DHCP primer&lt;/h2&gt;

&lt;p&gt;These are the initial steps of DHCP:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Client -&amp;gt; Broadcast: DHCPDISCOVER  (“I need an IP”)&lt;/li&gt;
  &lt;li&gt;Server -&amp;gt; Broadcast: DHCPOFFER     (“Here’s one”)&lt;/li&gt;
  &lt;li&gt;Client -&amp;gt; Broadcast: DHCPREQUEST   (“I’ll take it”)&lt;/li&gt;
  &lt;li&gt;Server -&amp;gt; Broadcast: DHCPACK       (“OK”)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are all single UDP packets, targeted to the broadcast addresses of both link (e.g. MAC FF:FF:FF:FF:FF:FF) and network layer (e.g. IPv4 255.255.255.255).
Except packets sent by the STA, they have the AP’s MAC address as the destination address at the link layer.&lt;/p&gt;

&lt;p&gt;With the explanations before, we now know that OFFER and ACK are the packets which are likely to get lost, because they’re not ACK’d.&lt;/p&gt;

&lt;p&gt;To make matters worse, &lt;a href=&quot;https://www.ietf.org/rfc/rfc2131.txt&quot; title=&quot;RFC 2131: Dynamic Host Configuration Protocol&quot;&gt;RFC 2131&lt;/a&gt; dictates
exponential backoff for client-retransmits (e.g. 4s/8s/16s/…) if no reponse is received for DISCOVER or REQUEST.&lt;/p&gt;

&lt;p&gt;This should explain why initial (“cold boot”) DHCP negotiations may take a really long time.&lt;/p&gt;

&lt;h2 id=&quot;how-to-speed-things-up&quot;&gt;How to speed things up&lt;/h2&gt;

&lt;h3 id=&quot;use-proper-antennas&quot;&gt;Use proper antennas&lt;/h3&gt;

&lt;p&gt;There are certified module/external antenna combinations. If you can, use them. Not only DHCP will work better, but the overall performance will be much better.&lt;/p&gt;

&lt;h3 id=&quot;use-a-proper-dhcp-client-implementation&quot;&gt;Use a proper DHCP client implementation&lt;/h3&gt;

&lt;p&gt;… or use your DHCP client properly.&lt;/p&gt;

&lt;p&gt;What do I mean by that? What I’ve explained about DHCP is only the “cold boot” behaviour as you may know.
If you look at Figure 5 of &lt;a href=&quot;https://www.ietf.org/rfc/rfc2131.txt&quot; title=&quot;RFC 2131: Dynamic Host Configuration Protocol&quot;&gt;RFC 2131&lt;/a&gt;, there are many more
states in a DHCP client’s life. So if the device would persist its DHCP information and timer “T1” wouldn’t have expired, on reboot the DHCP client could simply
go through INIT_REBOOT-&amp;gt;REBOOTING-&amp;gt;BOUND with unicast packets.&lt;/p&gt;

&lt;h3 id=&quot;use-my-broadcast-bit-trick&quot;&gt;Use my BROADCAST bit trick&lt;/h3&gt;

&lt;p&gt;In every packet sent by the DHCP client, there’s a “BROADCAST bit”.&lt;/p&gt;

&lt;p&gt;This is what &lt;a href=&quot;https://www.ietf.org/rfc/rfc2131.txt&quot; title=&quot;RFC 2131: Dynamic Host Configuration Protocol&quot;&gt;RFC 2131 (4.1)&lt;/a&gt; says about the BROADCAST bit:&lt;/p&gt;

&lt;blockquote&gt;
   A client that cannot receive unicast IP datagrams until its protocol
   software has been configured with an IP address SHOULD set the
   BROADCAST bit in the &#39;flags&#39; field to 1 in any DHCPDISCOVER or
   DHCPREQUEST messages that client sends.  The BROADCAST bit will
   provide a hint to the DHCP server and BOOTP relay agent to broadcast
   any messages to the client on the client&#39;s subnet.  A client that can
   receive unicast IP datagrams before its protocol software has been
   configured SHOULD clear the BROADCAST bit to 0.  The BOOTP
   clarifications document discusses the ramifications of the use of the
   BROADCAST bit [21].
&lt;/blockquote&gt;

&lt;p&gt;So if the BROADCAST bit is set, the DHCP server will answer with a brodcast, if it’s cleared, it will answer unicast.
When sending OFFER, it’ll send to the IP address it offers.&lt;/p&gt;

&lt;p&gt;(Side note: The mentioned “BOOTP clarifications document” states the same.)&lt;/p&gt;

&lt;p&gt;If the DHCP client can be modified to send DISCOVER/REQUEST with a cleared BROADCAST bit and if the rest of the TCP/IP stack
can be made to accept unicast DHCP packets even if it hasn’t configured its IP yet, things will improve.&lt;/p&gt;

&lt;p&gt;In my case, I’ve changed the DHCP client (it’s was only a tiny change) so that the first packet of DISCOVER/REQUEST has
the BROADCAST bit cleared. Retransmits have it set to give bad DHCP server implementations a chance to answer.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;

&lt;p&gt;Update Feb 2021: There used to be an example here of how to have Segger’s embOS/IP behave
as described. I just went through the Changelog and noticed that in V3.30 this behaviour
has been implemented. See &lt;code&gt;IP_DHCPC_ConfigUniBcStartMode()&lt;/code&gt;.&lt;/p&gt;
</content>

			
				<category term="code" />
			
				<category term="embedded" />
			
			
				<category term="embedded" />
			
				<category term="network" />
			

			<published>2016-06-05T00:00:00+00:00</published>
		</entry>
	
		<entry>
			<id>https://knzl.at/parser-generators-embedded/</id>
			<title>Using byacc+Ragel for memory efficient parsers</title>
			<link href="https://knzl.at/parser-generators-embedded/" rel="alternate" type="text/html" title="Using byacc+Ragel for memory efficient parsers" />
			<updated>2014-07-01T00:00:00+00:00</updated>

			
				
				<author>
					
						<name>seb</name>
					
					
					
				</author>
			
			<summary>How to use byacc and Ragel in tandem to generate parsers suitable for embedded targets that have little memory.</summary>
			<content type="html" xml:base="https://knzl.at/parser-generators-embedded/">&lt;p&gt;Parser and lexer generators are great tools and there is little reason to knit parsers or lexers (aka tokenizers) yourself.&lt;/p&gt;

&lt;p&gt;If your (embedded) target is short on memory, the used tools have to be picked carefully, as not many of them are designed with memory-efficiency in mind.&lt;/p&gt;

&lt;p&gt;I’ve found &lt;a href=&quot;http://invisible-island.net/byacc/byacc.html&quot; title=&quot;Berkeley Yacc&quot;&gt;byacc&lt;/a&gt; and &lt;a href=&quot;http://www.complang.org/ragel/&quot; title=&quot;Ragel State Machine Compiler&quot;&gt;Ragel&lt;/a&gt;
to be a great combination with both of them generating extremely tight code.&lt;/p&gt;

&lt;p&gt;Want to know more about them and other tools? Read on!&lt;/p&gt;

&lt;!--more--&gt;

&lt;p&gt;These are the requirements:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Generated code depends on little or no runtime&lt;/li&gt;
  &lt;li&gt;The grammar should be usable for generation to other languages, e.g. Java or C# with little effort&lt;/li&gt;
  &lt;li&gt;Memory-overflow conditions should be detected and handled gracefully&lt;/li&gt;
  &lt;li&gt;Generated code should use as little RAM as possible, possibly statically allocated&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There’s a table of available tools on &lt;a href=&quot;https://en.wikipedia.org/wiki/Comparison_of_parser_generators&quot; title=&quot;Wikipedia: Comparison of parser generators&quot;&gt;Wikipedia&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id=&quot;the-parser-generator-byacc&quot;&gt;The parser generator: byacc&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://invisible-island.net/byacc/byacc.html&quot;&gt;Byacc&lt;/a&gt; (“Berkeley Yacc”) is a really nice Yacc-implementation, which generates an &lt;a href=&quot;https://en.wikipedia.org/wiki/LALR_parser&quot;&gt;LALR&lt;/a&gt;-parser.
It doesn’t have all the features that &lt;a href=&quot;http://en.wikipedia.org/wiki/GNU_bison&quot;&gt;GNU bison&lt;/a&gt; (another Yacc variant) offers but it does produce nicer and tighter code.
No wonder, as it seems that both bison and byacc have initially been written by the same person (a Robert Corbett), with byacc having been written after bison.&lt;/p&gt;

&lt;p&gt;Byacc basically generates a few (ROMable) tables, optional debug-code and the parsing-logic.
All of its dynamic allocations happen in one function called “yygrowstack”, which could be easily changed to use static memory only.&lt;/p&gt;

&lt;p&gt;Like bison, it can generate a “pure” (reentrant) parser and can be given context, so the same parser can have multiple instances.&lt;/p&gt;

&lt;p&gt;One thing isn’t ideal, which is that the initial stack size (YYINITSTACKSIZE) can’t be configured.
That’s a pity, because in my case an initial stack size of 32 (vs. the default 500) is enough in all relevant cases.
The stack isn’t the execution stack, but the stack where the shift/reduce operations are being performed on.
So this isn’t bytes, but the number of tokens on the stack.&lt;/p&gt;

&lt;p&gt;Talking about the token stack: You should know that If you’re freeing resources connected to a token (e.g. free() on a pointer in the YYSTYPE-union) in the action code then this code may not be called on parse errors.&lt;/p&gt;

&lt;p&gt;To change YYINITSTACKSIZE, byacc’s skeleton.c can be patched or alternatively the generated file can be changed with sed or CMake’s file/string.&lt;/p&gt;

&lt;p&gt;This change fulfills Req #4. Stack-overflows are detected and reported (Req #3),
the grammar can be used for Yacc-implementations that generate for other languages (Req #2) and the generated code only depends on memset() and realloc().&lt;/p&gt;

&lt;h2 id=&quot;the-lexer-generator-ragel&quot;&gt;The lexer generator: Ragel&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://www.complang.org/ragel/&quot;&gt;Ragel&lt;/a&gt; is actually more than a lexer generator, it’s a “State Machine Compiler”.
Having used it for the first time, I’m sure to return to it more often, it looks great.&lt;/p&gt;

&lt;p&gt;Even if abused for “just” generating lexers, the generated code is great.
A few (ROMable) tables, the logic code and the action code interweaved and that’s all. No allocations, no dependencies, nothing.&lt;/p&gt;

&lt;p&gt;Ragel can also generate for different languages, fulfilling Req #2.&lt;/p&gt;

&lt;h2 id=&quot;having-them-work-in-tandem&quot;&gt;Having them work in tandem&lt;/h2&gt;

&lt;p&gt;There’s not much more to be said, check out the &lt;a href=&quot;https://github.com/sebknzl/byacc-ragel&quot;&gt;example I’ve put up at GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It shows how to use them together and how to have multiple instances of a parser.&lt;/p&gt;

&lt;p&gt;That’s it! Like always, questions and comments welcome.&lt;/p&gt;

&lt;h2 id=&quot;other-tools&quot;&gt;Other tools&lt;/h2&gt;

&lt;p&gt;I’ve looked at other tools which I eventually didn’t use. That’s what I found out about them:&lt;/p&gt;

&lt;h3 id=&quot;cocor&quot;&gt;Coco/R&lt;/h3&gt;

&lt;p&gt;&lt;a href=&quot;http://www.ssw.uni-linz.ac.at/Coco/&quot; title=&quot;Coco/R official page&quot;&gt;Coco&lt;/a&gt; has a nice EBNF-syntax and supports many languages (Req #2).&lt;/p&gt;

&lt;p&gt;It generates a &lt;a href=&quot;https://en.wikipedia.org/wiki/Recursive_descent&quot;&gt;recursive descent&lt;/a&gt; (LL-) parser,
which is the kind of parser you would write by hand. Hence, Coco/R generates really nice and readable code with the action-code cleanly interweaved.&lt;/p&gt;

&lt;p&gt;Unfortunately, the lexer is unusable (C++ variant, version 2012-01-02) for this case:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Allocates a lot of heap (60 kB)&lt;/li&gt;
  &lt;li&gt;Limited to wchar_t-Strings with its own string-functions (instead of std::basic_string&amp;lt;T&amp;gt;)&lt;/li&gt;
  &lt;li&gt;Lots of allocations&lt;/li&gt;
  &lt;li&gt;Dependency on wprintf, wcs*&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Coco/R supports custom lexers, so I exchanged Coco’s lexer with a Ragel-lexer.&lt;/p&gt;

&lt;p&gt;Eventually I found out that the generated parser may use a lot of stack, sometimes over 6 kB – yes, that can be too much.&lt;/p&gt;

&lt;p&gt;The problem is recursive descent parsers in combination with a grammar that has lots of precedence-levels,
like e.g. &lt;a href=&quot;http://www.difranco.net/compsci/C_Operator_Precedence_Table.htm&quot;&gt;C-style expressions&lt;/a&gt; with 15 or more of them.&lt;/p&gt;

&lt;p&gt;One precedence level results in one grammar rule which in turn results in one function call.
If there are over 15 calls until you finally hit a terminal and then have a rule with parentheses
which make the parser start at the top rule again and then there may be another parenthesis which… well, you get the idea.&lt;/p&gt;

&lt;p&gt;This is where the 6 kB come from: The stack frame of one method (i.e. grammar rule) may be 64 bytes or
more in size (this, parameters, local vars, registers) and the parser-input can easily result in a 100 frames deep callstack.&lt;/p&gt;

&lt;p&gt;Another serious drawback is that there’s no built-in way of detecting stack overflows (Req #3). The stack may just overflow and that’s that.&lt;/p&gt;

&lt;h3 id=&quot;others&quot;&gt;Others&lt;/h3&gt;

&lt;ul&gt;
  &lt;li&gt;ANTLR: &lt;a href=&quot;http://www.antlr3.org/&quot;&gt;v3&lt;/a&gt; supports C/C++, but it seems to have a big &lt;a href=&quot;http://www.antlr3.org/download/C/&quot;&gt;runtime&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;http://sablecc.org/&quot;&gt;SableCC&lt;/a&gt;: Supports C/C++ with “&lt;a href=&quot;http://www.mare.ee/indrek/sablecc/&quot;&gt;Alternative output&lt;/a&gt;”, but not with ROMability in mind (tables aren’t const)&lt;/li&gt;
  &lt;li&gt;(f)&lt;a href=&quot;http://en.wikipedia.org/wiki/Lex_%28software%29&quot;&gt;lex&lt;/a&gt;: depends on stdio and FILE and all that stuff&lt;/li&gt;
&lt;/ul&gt;
</content>

			
				<category term="code" />
			
				<category term="embedded" />
			
			
				<category term="C/C++" />
			
				<category term="embedded" />
			
				<category term="parser" />
			

			<published>2014-07-01T00:00:00+00:00</published>
		</entry>
	
		<entry>
			<id>https://knzl.at/cmake-debhelper/</id>
			<title>CMakeDebHelper: Using debhelper with CMake/CPack</title>
			<link href="https://knzl.at/cmake-debhelper/" rel="alternate" type="text/html" title="CMakeDebHelper: Using debhelper with CMake/CPack" />
			<updated>2013-11-30T00:00:00+00:00</updated>

			
				
				<author>
					
						<name>seb</name>
					
					
					
				</author>
			
			<summary>Making CMake/CPack and debhelper play well together.</summary>
			<content type="html" xml:base="https://knzl.at/cmake-debhelper/">&lt;p&gt;CMake/CPack is great for quickly packaging your stuff for Debian.&lt;/p&gt;

&lt;p&gt;However for instance, you may have programmed a daemon and want to let debhelper help you with update-rc.d-calls in your postinst/postrm-scripts.
Also, you may want to easily package cron.d-rules. There’s a debhelper for &lt;em&gt;everything&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;CPack does not let you use them without further ado, as it’s built to not rely on anything else.&lt;/p&gt;

&lt;p&gt;Here’s my way of making CPack and debhelper really good friends: CMakeDebHelper.&lt;/p&gt;

&lt;!--more--&gt;

&lt;p&gt;Arguably, it would be more like the “Debian-way” to actually use Debian’s tools for packaging.
However, this basically assumes that you’re in the role of a package-maintainer, which may not always be the case.&lt;/p&gt;

&lt;p&gt;In my case, I’ve written software that is deployed to clients as a Debian-package and
I prefer my build-system (CMake) to be in control of building &lt;em&gt;and&lt;/em&gt; packaging.&lt;/p&gt;

&lt;p&gt;Since you’ve found this post, you probably already know about the benefits of debhelpers. For those who don’t, here’s an example:&lt;/p&gt;

&lt;p&gt;When packaging for Debian, you usually type up scripts to execute after installation (“postinst”) or after removal (“postrm”), among others.
A package containing a daemon usually includes stuff for managing the “rc.d”-links through calling “update-rc.d”.&lt;/p&gt;

&lt;p&gt;No need to make up that code yourself, the debhelper “dh_installinit” can add that code for you! Look what it generates for example:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# Automatically added by dh_installinit&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; -x &lt;span class=&quot;s2&quot;&gt;&quot;/etc/init.d/cmakedh&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then
        &lt;/span&gt;update-rc.d cmakedh defaults &amp;gt;/dev/null
        invoke-rc.d cmakedh start &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$?&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# End automatically added section&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It also generates the script to run before removal (“prerm”) itself:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;set&lt;/span&gt; -e
&lt;span class=&quot;c&quot;&gt;# Automatically added by dh_installinit&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; -x &lt;span class=&quot;s2&quot;&gt;&quot;/etc/init.d/cmakedh&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then
        &lt;/span&gt;invoke-rc.d cmakedh stop &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;exit&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$?&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# End automatically added section&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you’re anything like me, you’ll really want to leverage functionality like that!&lt;/p&gt;

&lt;p&gt;There’s much more stuff, have a look at the &lt;a href=&quot;http://www.debian.org/doc/manuals/maint-guide/&quot; title=&quot;Debian New Maintainers&#39; Guide&quot;&gt;Debian New Maintainers’ Guide&lt;/a&gt; for more information.&lt;/p&gt;

&lt;p&gt;So, with my &lt;em&gt;CMakeDebHelper&lt;/em&gt; you’ll easily go from such an input:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;.
├── CMakeLists.txt
├── CPackConfig.cmake
├── cmake
│   ├── CMakeDebHelper.cmake
│   └── CMakeDebHelperInstall.cmake
├── debian
│   ├── CMakeLists.txt
│   ├── cmakedh.cron.d.in
│   ├── cmakedh.init.in
│   ├── cmakedh.postinst.in
│   └── cmakedh.postrm.in
└── src
    ├── CMakeLists.txt
    └── main.c
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;to a Debian-package with these contents:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;new debian package, version 2.0.
 size 3690 bytes: control archive=850 bytes.
      40 bytes,     2 lines      conffiles            
     201 bytes,    10 lines      control              
     154 bytes,     3 lines      md5sums              
     458 bytes,    30 lines   *  postinst             #!/bin/sh
     425 bytes,    29 lines   *  postrm               #!/bin/sh
     169 bytes,     7 lines   *  prerm                #!/bin/sh
 Package: cmakedh
 Version: 1.0.0
 Section: devel
 Priority: optional
 Architecture: i386
 Depends: libc6 (&amp;gt;= 2.0), make, rsync, adduser, liblog4cpp5, zlib1g, libboost-system1.49.0, libboost-regex1.49.0, libboost-filesystem1.49.0
 Installed-Size: 6
 Maintainer: seb &amp;lt;seb@asdf&amp;gt;
 Description: Package summary

drwxr-xr-x root/root         0 2013-11-30 16:01 ./usr/
drwxr-xr-x root/root         0 2013-11-30 16:01 ./usr/bin/
-rwxr-xr-x root/root      5360 2013-11-30 16:01 ./usr/bin/runme
drwxr-xr-x root/root         0 2013-11-30 16:01 ./etc/
drwxr-xr-x root/root         0 2013-11-30 16:01 ./etc/init.d/
-rwxr-xr-x root/root        35 2013-11-30 16:01 ./etc/init.d/cmakedh
drwxr-xr-x root/root         0 2013-11-30 16:01 ./etc/cron.d/
-rw-r--r-- root/root        24 2013-11-30 16:01 ./etc/cron.d/cmakedh
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The ham and a working example can be found &lt;a href=&quot;https://github.com/sebknzl/cmake-debhelper&quot; title=&quot;cmake-debhelper&quot;&gt;on GitHub&lt;/a&gt;, improvements welcome!&lt;/p&gt;
</content>

			
				<category term="code" />
			
			
				<category term="build" />
			
				<category term="cmake" />
			
				<category term="debian" />
			

			<published>2013-11-30T00:00:00+00:00</published>
		</entry>
	
		<entry>
			<id>https://knzl.at/logitech-media-server-in-a-chroot/</id>
			<title>Running Logitech Media Server in a chroot on Debian Wheezy</title>
			<link href="https://knzl.at/logitech-media-server-in-a-chroot/" rel="alternate" type="text/html" title="Running Logitech Media Server in a chroot on Debian Wheezy" />
			<updated>2013-10-09T00:00:00+00:00</updated>

			
				
				<author>
					
						<name>seb</name>
					
					
					
				</author>
			
			<summary></summary>
			<content type="html" xml:base="https://knzl.at/logitech-media-server-in-a-chroot/">&lt;p&gt;&lt;code&gt;
!!! This is outdated information. Left here for reference. !!!
&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Oh no, another chroot-tutorial! This time Logitech Media Server gets jailed.
If you only have it running locally it’s not necessary to imprison it, but if you have it running on a public IP it is.
Big software with plugins and open ports just creates this chroot-urge deep inside of me. It’s quick and easy, read on!&lt;/p&gt;

&lt;!--more--&gt;

&lt;p&gt;So, what do I want?&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;A minimal Debian at /var/local/squeezebox&lt;/li&gt;
  &lt;li&gt;A Logitech Media Server chrooted to that directory running as a certain user&lt;/li&gt;
  &lt;li&gt;Both the minimal Debian and the Media Server should be easily upgradeable through apt and dpkg&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;installation&quot;&gt;Installation&lt;/h2&gt;

&lt;p&gt;Install “cdebootstrap” and run these commands as root:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;cdebootstrap -f minimal --include apt,apt-rdepends wheezy /var/local/squeezebox&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Afterwards there’ll be a minimal Debian in /var/local/squeezebox.&lt;/p&gt;

&lt;p&gt;Fetch the latest Media Server Debian package &lt;a href=&quot;http://www.mysqueezebox.com/download&quot; title=&quot;Logitech Media Center download&quot;&gt;here&lt;/a&gt; and put it into our new chroot.&lt;/p&gt;

&lt;p&gt;Then, start a chrooted bash by running this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;chroot /var/local/squeezebox /bin/bash -l&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then, we’ll do some setting up:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# To avoid some errors&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;export &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;LANG&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;C.UTF-8
 
&lt;span class=&quot;c&quot;&gt;# Install the deb, there&#39;ll be unresolved dependencies!&lt;/span&gt;
dpkg -i logitechmediaserver_7.7.3_all.deb
 
&lt;span class=&quot;c&quot;&gt;# Make sure we&#39;re getting security updates&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;deb http://security.debian.org wheezy/updates main&quot;&lt;/span&gt; &amp;gt;&amp;gt; /etc/apt/sources.list
 
&lt;span class=&quot;c&quot;&gt;# Fetch available packages&lt;/span&gt;
apt-get update
 
&lt;span class=&quot;c&quot;&gt;# Make sure everything required by logitechmediaserver is pulled in&lt;/span&gt;
apt-get -f install&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the next step we’ll change the UID and GID of the user “squeezeboxserver” to the “real” UID:GID we want the server to be running as. In my case, it should be seb:seb (1000:1000 on my system).&lt;/p&gt;

&lt;p&gt;Then (still in the chrooted shell):&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# First, remember the original UID, it was 101 on my system&lt;/span&gt;
id -u squeezeboxserver

&lt;span class=&quot;c&quot;&gt;# The user is in group nogroup, let&#39;s put it into a dedicated group&lt;/span&gt;
addgroup squeezeboxserver
usermod -g squeezeboxserver squeezeboxserver

&lt;span class=&quot;c&quot;&gt;# Now change it to the ids it should be running as&lt;/span&gt;
usermod -u 1000 squeezeboxserver
groupmod -g 1000 squeezeboxserver

&lt;span class=&quot;c&quot;&gt;# Re-own its files to this uid:gid. Change 101 to whatever the command in line 2 spat out &lt;/span&gt;
find / -uid 101 -exec chown squeezeboxserver:squeezeboxserver &lt;span class=&quot;o&quot;&gt;{}&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As a precaution, let’s remove the suid-bit from all binaries that have it. The following command is meant to be run in the chrooted shell, &lt;em&gt;be careful&lt;/em&gt;!&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;find / -perm +6000 -type f -exec chmod -s &lt;span class=&quot;o&quot;&gt;{}&lt;/span&gt; &lt;span class=&quot;se&quot;&gt;\;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id=&quot;removing-unneeded-packages&quot;&gt;Removing “unneeded” packages&lt;/h2&gt;

&lt;p&gt;This step is not recommended, it’s just an “academic exercise”. I just keep it here as reference. Go to the next step.&lt;/p&gt;

&lt;p&gt;It removes all the packages that aren’t required for operation and this will break updating at some point.
I was curious how to go about it and this is the result. Again, &lt;em&gt;be careful&lt;/em&gt;, this is meant to be run in the chrooted shell!&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;# Get a list of packages required for the packages mentioned on the command line&lt;/span&gt;
apt-rdepends coreutils bash findutils sed apt dpkg libpam-runtime logitechmediaserver 2&amp;gt;/dev/null | grep -v &lt;span class=&quot;s1&quot;&gt;&#39;^ &#39;&lt;/span&gt; | sort | uniq &amp;gt; debs-needed
 
&lt;span class=&quot;c&quot;&gt;# Get a list of installed packages&lt;/span&gt;
dpkg-query -W -f&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&#39;${Package}\n&#39;&lt;/span&gt; | sort | uniq &amp;gt; debs-installed
 
&lt;span class=&quot;c&quot;&gt;# Remove those packages which are in debs-installed but not in debs-needed, possibly removing essential packages&lt;/span&gt;
dpkg -P --force-remove-essential &lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;comm -23 debs-installed debs-needed&lt;span class=&quot;sb&quot;&gt;`&lt;/span&gt;
 
apt-get clean&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id=&quot;starting-the-server&quot;&gt;Starting the server&lt;/h2&gt;

&lt;p&gt;We’re going to start the server as the specific user directly, no root-privileges are ever needed. The following commands are run outside the chroot (hit Ctrl-D if you’re still in the chrooted shell).&lt;/p&gt;

&lt;p&gt;There’s just one more thing to take care of, chowning the run-directory for the start-stop-daemon’s PID-file:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;chown -R seb:seb /var/local/squeezebox/run/&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then we can start the server by running this as root:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;chroot --userspec&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1000:1000 --groups&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1000 /var/local/squeezebox /etc/init.d/logitechmediaserver start&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I prefer dropping the user-privileges at this stage.
It’s probably safe without the userspec/groups-stuff because the start-script will drop its rights through start-stop-daemon anyway,
but better safe than sorry.&lt;/p&gt;

&lt;p&gt;Chroot’s man-page claims that names instead of numeric ids can be used, but it doesn’t seem to work.
There’s one more catch: Without the –groups-parameter, the resulting proc will still have 0 in its groups! Bug or feature?&lt;/p&gt;

&lt;p&gt;That should be all. If you want the server to be started at boot-time, a simple script like&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;
chroot --userspec&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1000:1000 --groups&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1000 /var/local/squeezebox /etc/init.d/logitechmediaserver &lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;in /etc/init.d/ of the “real” filesystem should do the job.&lt;/p&gt;

&lt;p&gt;For upgrading, simply launch a chrooted bash as shown above and use dpkg and apt-get as always.&lt;/p&gt;

&lt;p&gt;That’s all for today!&lt;/p&gt;

</content>

			
				<category term="administration" />
			
			
				<category term="chroot" />
			
				<category term="squeezebox" />
			
				<category term="debian" />
			

			<published>2013-10-09T00:00:00+00:00</published>
		</entry>
	
		<entry>
			<id>https://knzl.at/krawall/</id>
			<title>Krawall GBA on GitHub</title>
			<link href="https://knzl.at/krawall/" rel="alternate" type="text/html" title="Krawall GBA on GitHub" />
			<updated>2013-07-18T00:00:00+00:00</updated>

			
				
				<author>
					
						<name>seb</name>
					
					
					
				</author>
			
			<summary></summary>
			<content type="html" xml:base="https://knzl.at/krawall/">&lt;p&gt;Krawall GBA is an XM/S3M modplayer / soundsystem for the Gameboy Advance that I was developing 10 years ago.
Back then, I successfully licensed it to quite some game developer studios and it was used in games like “The Sims”, “Spiderman”, “Lord of the Rings” and others.&lt;/p&gt;

&lt;p&gt;I’ve removed the dust, updated it to be compatible with the latest &lt;a href=&quot;http://devkitpro.org/&quot;&gt;devkitPro&lt;/a&gt; and rewritten its build-system,
also I put it under the LGPL. Get it at &lt;a href=&quot;https://github.com/sebknzl/krawall&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
</content>

			
				<category term="code" />
			
			
				<category term="embedded" />
			
				<category term="krawall" />
			
				<category term="gba" />
			

			<published>2013-07-18T00:00:00+00:00</published>
		</entry>
	
</feed>