Pages

May 31, 2010

Conclusive proof that there is no way to (accidentally) brick s5l8900

In the process of testing NOR, I did a pretty lulzy thing. Remember what I said earlier about the memory controller possibly ignoring the first 4 bits? Well, the NOR device ignores the top 12 bits, since it's only 1 MB in total size. This makes a lot of sense. All the designers have to do is basically not wire up some parts of the address bus. So whether you try to address 0x0 or 0x100000 on the NOR, it looks the same to it.

The problem came about because I attemped to add too many images to NOR; a few 140 KB iBoot images can add up pretty quickly. The last one I added ended up shooting into the range reserved for NVRAM (at the end of NOR) and then "wrapping around" to clobber SysCfg, IMG2, and part of the LLB. =P

Hahaha, that's the equivalent of shooting yourself simultaneously in every vital organ. SysCfg stores your SERIAL NUMBER and other unique, irreplaceable pieces of information. The NVRAM contains information iBoot needs to boot up the kernel. The LLB is the thing that securebl tries to load in order to access everything else on NOR and bootstrap iBoot. As the coup de grace, IMG2 contains information that allows the LLB and iBoot to find where the Img2 data starts, so that they can be loaded. This mistake basically was the equivalent of erasing the entire NOR: Every single piece of information on it was rendered unusable. :P

Luckily, as the first test of my NOR driver, I had made a dump of my original NOR, so I was able to restore the SysCfg information. The interesting bit about all this is that you don't even have to do a restore and lose all your data on the NAND even, if you're clever. What I did was let iTunes talk to DFU mode to get into an iBoot. The iPhone actually has a pretty standard DFU mode, as defined by the USB standard. It reports itself as having the correct class, and OpenMoko's dfu-util manages to get, well, something with it. It successfully uploads the iBSS 8900 file (looking at a USB dump, it looks like just the entire file with the 8900 header, signatures, certificates, etc.) but reports that the firmware is corrupted. So at least it seems to use standard status indicators, etc. However, since I couldn't get dfu-util to work, I just used iTunes and pulled the cable out right after it finishes uploading the iBSS. DFU mode doesn't actually change the NOR, it just loads iBSS into memory and executes it. So after this process is done, iBSS will be loaded and you can connect to it via iBooter.

If you had pulled out the cable just a little too late, you can even see the commands iTunes executed on iBSS in the scrollback, Like setpicture and bgcolor. =P

Using the loaded 1.1.4 iBSS, you can bootstrap the necessary actions to restore your NVRAM from backup. I will talk about that in more detail in a future post. But the upshot is, even if you complete kill your "bootloader", and indeed, everything you can possible write to on the iPhone, you can still get things back to normal. :)

Unfortunately, I probably won't have a chance to work on iPhoneLinux stuff much this weekend. I have already been activated by the Dev Team because you-know-what is happening. Time to hax.

May 30, 2010

When the bootloader is not the bootloader

I'm going to address the two comments I received in this post. This basically has nothing to do with Linux, and more to do with iPhone hacking. There's a lot of confusion around with the jailbreak/unlock. The two comments basically hit upon the main points. The main confusion centers around the fact that when you buy an iPhone, you're not just getting a computer, you're getting TWO computers.

What I'm interested in is the S5L8900, the thing that runs the iPhone software. There is another device called the commboard, which has its own processor, nonvolatile memory, boot sequence and everything. It's barely an oversimplification to state that the system board (the S5L8900) and the commboard can only communicate with each other over a serial UART. That is, the only way the system board can control the commboard is with human-readable AT commands! Not very low level at all; they're not very integrated. Being able to hack kernel mode code like iBoot does not give us any more access than we had through minicom on a jailbroken iPhone.

kavkan asked me if iPhone Linux would obviate the unlocks. He then started talking about putting on third-party applications, etc. Putting third party applications on your iPhone is usually referred to as jailbreaking: stuff we do on the S5L8900. When we say unlock, we're usually mean a SIM-unlock. That necessarily means breaking a whole other, entirely distinct, set of security that's on the commboard. A jailbreak makes it easier to do that (because you can now talk to the commboard with that serial UART I discussed earlier), but it's entirely separate.

marc asked me about "bootloader corruption" as it pertains to basebands. As I said earlier, the bootloader I am talking about is on the S5L8900. The baseband/commboard has its own bootloader and its own non-volatile memory (also NOR flash, probably the same bit of flash its bootloader and firmware sits on too). The recovery mechanism on the baseband is far less robust than the one on the S5L8900. The only sure way seems to be using that hardware testpoint to force it to accept a new bootloader, and even that can be defeated by carefully crafting the NOR contents. In other words, it sucks.

In addition, a lot of the problem is due to bad software overwriting the seczone with bad data, stuff that's unique to your phone. Therefore, information is irretrievably lost and there may not be a way to recover.

The disclaimer is, of course, I'm not a baseband expert. This stuff is only what I've surmised by hanging out with some of them. It's kind of funny. On the dev team, w___ and Zf (they're baseband guys) and I were talking about how little we each know about the others' work. We do pretty much the same work, but on different platforms. After I explained what we do on the S5L8900, I think w___ said that he did the same thing "only on the baseband, you have a man sitting on top that does stuff to you for unknown reasons". And for the S5L8900 people, we have a little black box connected to us that either magically works and lets us call people... or not.

May 29, 2010

How to fix a bricked iPhone

So how did I manage to FIX the problem I mentioned earlier? The reason I was so vague on the details is that I used a confidential iBoot vulnerability that we didn't want Apple to know even existed! This allowed me to bootstrap openiboot directly from a stock iBSS that was loaded through DFU mode. I still can't tell you exactly what it is, but since geohot already leaked the existence of it, I figure I can tell you it exists and is what I used. :)

Then, it was a simple matter of using openiboot's NOR engine to restore everything. I even can use the new image list parser and AES engine to have a very nice high level interface to the image list, allowing me to "pwn" just with openiboot; no ramdisk futzing around!

The AES code has been in SVN for awhile, but to anyone following jailbreaking news, it's probably obvious why I suddenly, out of the blue, decided to reverse it and write it. Haha. So the night that I committed the AES code, is the night the Dev Team first decrypted the new img3.

May 28, 2010

USB fixes

Just a post to indicate things are inching forward slightly. I've been working on debugging USB communications and it seems a lot more stable now. I was basically forced to because my old code only works on computers without usb 2.0, so that ruled out being able to easily work on this project with anything approaching a modern computer. The problem was that I avoided reading the official USB specs (those things are usually overly locutious) and tried to learn instead from sites such as USB in a Nutshell. Unfortunately the driver then failed to properly respond to the device qualifier descriptor which led to epic fail in USB 2.0. The embarrassing thing is iBoot does send this descriptor, but I figured it must be a vendor specific one at the time.

Cmw made me a cable that let's me do serial and USB comm at the same time, which helped a lot in working out the bugs. I'd say it's fairly reliable now; enough for other developers without a serial cable to come in. So how about it, guys?

I've also started to scratch the surface of the NAND driver. Unfortunately, even the lowest level functions are enormously complex. The higher level wear leveling code and data structures even aside. A great deal of it seems to belong to Samsung, since I've found some creepily similar C code lurking around online. Unfortunately, I can't find a complete enough copy of it.

And yes, I'm aware of Android and their source release and yes, I know what you're thinking.

May 27, 2010

LCD driver done?

I had a lot of trouble getting the LCD driver to work. Everything seems to be fine except that when I try to write to the memory address range reserved for the LCD's gamma tables, it doesn't register. It's as if some clock or some device hadn't gotten turned on or something. Therefore, after loading openiboot from iBoot, the screen gets all screwed up.

However, if you load iBEC from iBoot, the screen doesn't get screwed up: you can still use bgcolor and everything works. I thought that meant at first there was something wrong with my LCD init code. I spent a frustrating day carefully auditing it for errors, and I did find two bugs that I fixed, but unfortunately it did not have any effect on the main problem. I got as far as I could with static methods so I decided to perform a series of experiments.

First, I had some trouble chainloading iBoot and iBEC from openiboot. There was a series of fails that I fixed along the way: trouble with USB send (just a silly typo in the client), trouble getting the resulting thing to execute in memory (you've gotta turn off the CPU caches, disable MMU and interrupts for it to work properly. It also can't be run as part of an ISR because, well, iBoot expects to be able to receive interrupts, so I had to move the command processor onto the main thread and just have the ISR queue up commands for the main thread to process). Anyway, those were eventually fixed.

My experiments showed that after openiboot did its inits, chainloaded iBoot and iBEC was unable to reinit the LCD properly (they had the same problem). I narrowed the problem down to the place in power.c where I "turn off" the LCD controller. This happened in the 114 iBoot, so I thought it was necessary. Analyzing the newer 2.x iBoots, that routine was actually removed. Since I am reasonably confident that my syrah_init is functionally identical to their merlot_init and this that power init that when present, causes LCD init to fail in all cases and when absent, allows LCD init to succeed in all cases, I'm pretty sure that's the problem.

So I went ahead and removed it. This may or may not mean I am actually depending on the iBoot that I chainloaded openiboot from for the LCD init. We'll see after I try to replace iBoot entirely in the bootchain.

Anyway, USB is solid as a rock now seemingly and chainloading seems to be working quite well. I'm actually able to load iBoot from NOR, patch it in memory, and then execute it from openiboot. This probably means I'm ready to try flashing the thing again.

May 26, 2010

Now Open iboot booting for iPhones and iPods!


Well, it's booting. Sort of.

I had some trouble getting the flashed version of it to work because for some reason, 0x0 was not mapped to 0x18000000 when openiboot was loaded. Since all the exception vectors are at 0x18000000, bad ones were being called whenever there was any sort of interrupt. Basically, I just said screw it and rebased the whole program into 0x0. It will basically overwrite whatever exception vector is currently running without worrying about the MMU and such. However, this basically does imply that I don't really understand how the MMU works, so that will have to be fixed.

The end result is what you see above.

The other major roadblock is that the gamma tables remain broken. Even after I chainload iBEC or iBoot over openiboot (as I have done there). The OS boots and everything... just with some really psychadelic colors. =P

So LCD remains a big problem and so does the MMU. But hey, it boots and works (sort of).

Update: LCD now partially fixed. I still need to figure out how to turn the backlight on, but at least chainloaded iPhone OS has normal colors now. =P

May 24, 2010

Boot menu done for All Latest iPhones!


Well, that was quick. See, I can actually get things done pretty quickly when it doesn't consisting of banging my head against machine code until it starts making sense. When I actually have the drivers, things like this are easy.

You can use the Hold button to toggle between the menu items (and the option will be highlighted). You can choose the home button to select it. The "openiboot console" option takes you to the command-line interface similar to the one I demonstrated in the last post (you do have to be plugged in via USB and using the openiboot client to talk to it). The "iPhone OS" option chainloads a copy of iBoot stored in NOR under another identifier ('ibot' becomes openiboot and 'ibox' becomes the actual iBoot). I got that set up with a slightly modified version of the QuickPwn ramdisk, but in the future an installer made from a modified version of LogoMe can be run from userland to install openiboot. It's also possible to get openiboot to install openiboot (much like the way GRUB can do it); I'll probably work on that next.

So if anyone likes living on the bleeding edge, they could do that. =P

Most of the hard part was me failing at GIMP putting together the boot menu graphics. I appealed to you blog readers for graphics before, but basically no one responded. Now that there is a working model of what I sort of want, I hope there will be more of a response.

So, please please please redesign the boot menu for me. And possibly come up with a logo for the project we can stick on there. If you're good at this sort of thing, or know someone who is, please put them in touch. This stuff will obviously get a lot of attention in the future and we need nice eye-candy. Thanks!

The Porting an OS for New Android iPhone and iPod

I've been getting a lot of questions from people that seem to reflect a basic misunderstanding of what it takes to port an operating system onto a new platform. People seem to think that just by writing, say, a boot menu, means that we can stick Android or Windows or whatever onto a device because we can have a menu option for it.

Here's what it takes for an operating system to run on a device:
  • The code must be designed for the right CPU. (x86, ARM, PPC)
  • The code must be able to interact with the hardware in the way it expects.
Now, there are versions of Linux compiled in ARM (which the iPhone uses), there are even versions of Windows Mobile that are compiled in ARM. Why can't I, then, just stick Windows Mobile or Android (or another flavor of Linux) onto the iPhone and give it a whirl?

Because the code cannot interact with the hardware! That is, there are no Linux drivers or Windows Mobile drivers for the hardware that's on the iPhone. We're not even talking about things like the wi-fi won't work or anything silly like that. We're talking about big things, like not being able to start because it doesn't uncompress itself into RAM properly. We're talking about freezing the first time it has to wait for something to happen because it doesn't know how to run the hardware clocks and timers (which is CRITICAL for computers) and doesn't know when to start again.

Thus , if I tried to take some distribution of Linux or Windows or whatever, stick it in memory and start it, absolutely nothing will happen. That's right: nothing. There will be no output because it doesn't know how to run the display, or the USB, or serial. It probably won't even get to the first line of code that tells it to output something because so many things are broken.

So how can we get Linux to boot on the iPhone?

By teaching it how to run the hardware. We take the knowledge gained from getting that boot menu to display and graft it into the Linux kernel. It took an unbelievable amount of devices just to get the boot menu display: clock, timer, vic, mmu, spi, i2c, gpio, system controller, pmu, nor, uart, usb, lcd, buttons. Some of those may seem obvious to you, some work in the background to support the other devices. But all of those had to be reverse engineered and all of them will have to transplanted into the Linux kernel to even get something half-assed booting.

If all of those devices were required to get something as simple as boot menu up, can you imagine what would happen if you tried to boot an operating system that did not know how to run ANY of those devices?

We cannot modify the Windows Mobile kernel because it's closed source, and so there's no way to get it to run on the iPhone.

The critical misunderstanding, I think, is that people think somehow that the OS "sits on top" of the boot menu, and talks to the hardware through the boot menu. Therefore, you can have an "emulation layer" that lets Windows or Linux or whatever talk to the hardware, without having to alter Windows or Linux itself. This is completely false. An operating system, by definition, has direct access to the hardware. Nothing sits between it and the hardware. Once iBoot has loaded the iPhone OS, you can go ahead and wipe it clean from the NOR and the OS will keep running as usual. It's not "running", it's not used or loaded in any way except during the boot process.

The iPhone will never run Windows Mobile directly (virtualization would be possible albeit it would crawl on the iPhone). It will run Linux once we write the drivers for it based on our knowledge of the hardware. Android uses the Linux kernel, though they do modify it to a certain extent. Since the only really hardware dependent parts of an OS is in the kernel, presumably once we install the necessary drivers, Android will run just as well as Linux runs. However, not having even looked at Android's source yet, I really don't have a truly educated opinion at the moment, but let's just say that it's one of this project's primary goals.

Sorry this is so long, but intelligent explanations tend to be long.

P.S. Another question people ask a lot is how long will it take. I can't truly give a good answer to that, because it's sort of dependent on the schedules of the people who work on it, and it also depends on how fast it'll take to write the Linux drivers, and how many unexpected problems crop up. It could go really unexpectedly fast, or we could hit a roadblock. I think outside observers, just reading the commit logs and reading the blog has as much information as I do on how fast things are progressing, so you're free to come up with your own conclusions on how long it will take.

May 23, 2010

Installation, the PMU for iPhone

While I was waiting for CPICH to finish the first bits of the NAND FTL reverse engineering work, I've been trying to fill in some of the gaps we had in other places, such as the PMU. As promised, there is also now an easy way to install openiboot onto the iPhone. This is great because it will eventually lead to an even leaner and easier QuickPwn in the future.

One of the annoying parts about iBoot in recovery mode is that the thing refuses to charge the iPhone while sitting in recovery mode. The battery just eventually entirely drains. With the new PMU code, openiboot now recharges the battery, so programmers using it (read: me) can just have it sit on the console screen indefinitely. You can also do neat things like check the current battery voltage and check the power supply type the phone is charging from.

The "installation code" consists of porting over my knowledge of reading and modifying img3 files from working on the jailbreaks. I was too lazy to port over the entire xpwn framework, but I wrote up a "diet" version that is sufficient to read and modify img3 files in a limited fashion. img3 files are sort of the new native format of the main part of the NOR (just a bunch of img3 files concatenated together). The upshot is that you can load openiboot as an img3 through iBoot (just like sending an iBEC image) and then type "install" at the console and openiboot will be a permanent stage in your bootloader chain. =P

You can, of course, keep booting up to the iPhone OS as you always do by selecting the option in the boot menu. Installing openiboot isn't very useful except for hackers wanting to hack openiboot.

I also figured out how to parse and modify the NVRAM banks (storing environment variables like "auto-boot", etc.), which was actually pointless complicated (in my opinion). They have two banks consisting of a bunch of partitions with these headers that Apple uses a pointless one-byte custom checksum on. The entire bank is also checksumed with adler32. When NVRAM is modified, the oldest bank is overwritten with the data and becomes the newest bank (which is tracked by an epoch number on each bank). This is so if one bank becomes corrupted, the other can be used as a backup. However, NVRAM hardly contains anything high value so the value of all this trouble is doubtful. Being able to write to NVRAM, though, makes it possible to set auto-boot on and off within openiboot so that we can easily control whether or not to enter iBoot's recovery mode.

Someone asked me how "safe" it was to do the installation, etc. Well, I've been doing it every time I make an update these days, so it's fairly safe. The worst that can happen in the usual case is that you may be forced into a DFU mode restore. Everything will be undone with a restore. Early on, I did have bugs that really screwed things up so that a DFU mode restore was no longer possible, but even that was recoverable. I'll just go over how briefly:

The important thing is to have a backup of the NOR. As I described in a previous posting, it's possible to really screw things up if you erase the SysCfg section of the NOR. If you do that, the iPhone OS will refuse to boot at all since iBoot cannot properly populate the device tree for the kernel. Since restore ramdisks rely on XNU booting, this is Bad News Bears. In addition, the SysCfg section is device specific, so if you do not have a backup, it will be difficult to ever completely recover from erasing it.

Therefore, before you proceed, MAKE A BACKUP OF YOUR NOR. openiboot can do this for you (and subsequently restore your backup if things go wrong).

Load openiboot via loadibec and select the console. Connect with the oibc client. Type in: nor_read 0x09000000 0x0 0x100000

This will read all of NOR into memory. Then type: ~nordump.bin:0x100000

This will transfer the dump over USB onto your computer and save it as nordump.bin.

Supposing you filled the entire NOR with garbage somehow and are unable to boot. You have to get into openiboot to restore the NOR. The problem is that openiboot is only designed to operate in a post-LLB or post-Recovery Mode context, so it cannot be directly booted from DFU mode. Basically, you've got to load a pwned WTF, then a pwned iBSS, and then a pwned iBEC (all of which is available from a custom IPSW). After that, you can use loadibec to load openiboot. Then, you can restore the NOR thus:

!nordump.bin
nor_write 0x09000000 0x0 0x100000

After that, you can reboot and everything should be normal.

Also, I received a few responses for people volunteering to do the art. I'm not sure what the best thing would be, since I don't want anyone putting in effort for nothing, but we do want the best possible results. So, I'll be getting back to you guys about that.

May 22, 2010

Why iPhone Linux?

This is a post I wrote a long time ago, when this blog was first conceived. I decided to hold off on posting it, because I thought it'd be better to do some technical posts before waxing philosophically. I think it is still appropriate, so as we work on reverse engineering the NAND FTL, here's some food for thought.

Porting Linux to the iPhone is an arduous project. We will be trying to develop an entire suite of device drivers for undocumented hardware and then attempt to run a full-fledged operating system on it. This thread speculates "10 days" or "3 hours" as the amount of time it'd take to get Linux up and running on the iPhone. Perhaps this figure would be accurate on a x86 platform, or other platforms with hardware for which device drivers are already written or for which at least documentation is available, but we have no such luck on the iPhone.

This comment on a O'Reilly Radar article about NerveGas's iPhone Open Application Development book says, with perhaps a little too much vitriol for my taste, that developers should not waste time on the iPhone, a closed platform, and spend time more productively on OpenMoko or Android: truly open platforms. Apple should thus be punished for not making the iPhone open. His point is well-taken though. Reverse engineering Apple's code is inefficient and ought to be unnecessary. Why do I bother when I can just develop on an open platform instead with no such wasted effort?

Finally, I have faced skepticism even from my fellow Dev Team members when I first talked about this project. The iPhone already has a perfectly serviceable operating system that we can develop on. Why does it need another one? Sure, Linux might be cool, but what practical use would it have? How does it justify the tremendous amount of effort that would need to be put in?

So. Why do I bother? Why should we bother?

Part of the answer is that I don't choose which platform I hack on based on how hackable it is. I choose it based on how much I like it. I don't own an OpenMoko device; it simply doesn't look as polished as the iPhone, and support is lacking for it. It wouldn't make sense to buy it to use it, only to buy it to hack on it. While this may work for other people, it's simply not the way a (relatively) starving college student does things. As for the Android, I'm not too convinced about how amazing it will be from the videos I've seen and besides: It doesn't even exist yet! In general, the more people use a device, the more hackers use it, and thus the more it is hacked on. Usability frankly trumps hackability.

The other part of the answer is that iPhone Linux will actually be of tremendous value. There will be no more need to port applications over: The applications already run on the iPhone! Also, with a familiar kernel, we can do all kinds of things I've wanted to do: doing security related work with the wi-fi for example. Plus, knowledge that we are gaining/will have gained about the iPhone hardware will be of incredible practical value to the homebrew iPhone community. We've always wanted to be able to plug in the iPhone as a simple USB mass storage device. With USB and NAND FTL drivers, we can actually implement this ourselves.

Perhaps my most important point is how iPhone Linux will affect the various open platforms in development. The iPhone has revolutionized the way the market thinks about mobile computing and now several mobile platforms are in development: OpenMoko, Google's Android, and Mobile Ubuntu (thought the last is not targeted for phones). All of these projects are based on Linux, and "based on Linux" means that, by definition, they "use the Linux kernel" and the Linux kernel is exactly what we're porting. As long as the kernel works, the rest of the operating system will barely need to be touched at all! (fine print: provided that the working configuration of the kernel can support all the features the userland requires).

Imagine OpenMoko on the iPhone. Android on the iPhone. Ubuntu Mobile on the iPhone. Consumers will have choice, and not some Linux-hippie idealistic choice-for-the-sake-of-choice choice: All of these platforms have major momentum behind them and it is very possible they will end up being better than the iPhone's platform (have better UI, more application support, etc.). Also, imagine what it will mean for the developers of these platforms: A ready userbase of millions of users. If many people can already install and try out one of these platforms, it'll be far easier to attract users to buy the hardware, and developers to develop for the platform. Thus, I do not believe we are harming the open platforms by developing on the iPhone. In fact, if all goes well, we will be allowing them to conquer the Apple iPhone.

Of course, I know the reply to all of this. "That sounds good, now show me the code." It's important not to overpromise and underdeliver, so I will be very cautious. What I have just said is the hope, the best possible outcome. But just having that as a possibility is tantalizing enough to justify working on this project. However, to be honest, my original justification (as stated to the dev team) for working on iPhone Linux was "for Skillz.app", our facetious term for working on something merely to hone one's skill or to satisfy one's curiosity. But honestly, what did you expect from a "hacker"? :)

We have already made more progress with openiboot than many people have anticipated would ever happen. Reverse engineering drivers is a laborious process, but one that doesn't require the luck of finding a security vulnerability: It just happens slowly and steadily, rather than unpredictably. Presumably after the drivers are in place, the Linux kernel will "just work" without too many other changes, since it is designed to be relatively portable, so we ought not to have many problems. After the kernel works, I hope enough developers will become interested and a nice userland can be developed without too much trouble. The userland work is much less risky from a time-investment point of view.

May 21, 2010

iPhone NAND filesystem now readable!

Amazingly enough, the FTL_Read stuff from last night was pretty much correct! After that, it was relatively trivial to port over the HFS+ code I've already written (which was in pure C... finally that [fail] design decision has been vindicated =P).

As you can see in the screenshot below, with the latest Git revision, you can browse the filesystem from openiboot!


Next on the list is to port openiboot over to the iPod touch and iPhone 3G. It's probably just a matter of putting in different numbers for the GPIO ports, but we'll see.

After that, I will implement poorlad's bootmenu (which everyone seems to like).

After that, well... We have pretty much all the devices now, so we'll start looking at the Linux kernel. If you're a Linux kernel guy who would be willing to help (preferrably you have experience porting Linux to new ARM platforms), please leave a comment here. I can do most of the muscle work, but it'd be nice if someone can show me how to set up the source tree properly for the new port.

May 20, 2010

Porting drivers to Linux

We've made some progress on the USB gadget driver for Linux, and we're now running a generic serial gadget for communication. This implementation is important because USB is now a lot less laggy and things like ethernet over USB, etc., can eventually be supported, easing access.

We've also got pretty far with porting the NAND driver to Linux. Most of the read support is now there, and we've isolated the routines in the iPhone kernel where the raw hardware write occurs. CPICH and c1de0x are working on reversing it. Hopefully, it will be analogous enough to reads that it won't take a huge amount of time to work out.

This is different from reversing their FTL, however, which is a complicated slew of data structures, merge buffers and other exotic algorithms that take care of evenly distributing writes throughout the device and also making writes take less time.

I think reversing all of that would take too much time and effort. Instead, my proposal is to just reverse the hardware NAND writes. Instead of using a partition, we would have a loop-mounted root filesystem (similar to how Wubi is setup), with the root filesystem being a file on the Media partition. Since there's a non-empty file at that location, the FTL system, whatever it is, must create a one-to-one mapping from logical sectors to physical NAND pages. We can already read the mapping it creates (we have already reversed the read-side FTL code), and so all we have to do to alter the data is to write to the same pages we would've read from. Of course, this means that wear-leveling and bad block handling is not performed. However, if we use a filesystem that's aware of bad blocks and can wear-level (YAFFS or JFFS2), then it amounts to the same thing. The wear-leveling would then take place over the particular physical pages belonging to the rootfs image, rather than the entirety of the NAND. This would make the physical pages belonging to the rootfs image wear out a little faster than the rest of the NAND, but the actual effect of this should be inconsequential.

The additional benefit of this setup is that there's no repartitioning required, so setup is cinch. See this wiki document for specific proposed implementation details.

May 19, 2010

Poorlad's menu implemented; Porting issues resolved

Yesterday night, I merged in a branch I was working on for poorlad's menu. A version of that beautiful menu is now in Git. His menu included a version string at the bottom. We didn't have any way to keep track of versions and builds before, so this was actually a good idea that I had to implement. Because I didn't want to implement support for non-fixed width fonts, or add another space-consuming font, I just used the console font I was already using for that part. I also had to brighten the gradient on the bottom of the screen, since it was basically invisible due to gamma issues otherwise.

The border between the gradient and the "black" is clearly visible on my device. This is probably because of a gamma issue. When poorlad comes back, we can ask him to calibrate it more.

Otherwise, it looks pretty good! In order to make this possible, I added in stb_images.c, a great tiny little image library that can read PNG, JPEGs and even PSD files and does zlib decompression as an added bonus. This will be a great help if we decide to change things or need to add more stuff that consumes a lot of space. I also added in a basic function to perform alpha blending (albeit comparatively slowly).

Sadly, while I was busy making these changes, ius from IRC actually begun to implement poorlad's menu without me knowing about it, so we ened up duplicating each other's efforts. He was able to compile in zlib and libpng, but the cost was to inflate the final binary to 347 KB. Whereas taking out the old menu images, and adding small, compressed PNGs and the stb_images library instead actually made openiboot smaller than it was before! His decision to preblend the images, rather than attempt alpha blending on the device, was probably more optimal from a performance perspective.

Steven Troughton-Smith told me on Twitter that he has actually implemented his own boot menu as well. I'm not sure if he used the new PNG code or not, but the new code makes it pretty easy for a competent programmer to add in whatever menu they would like. I'd tell everyone to skin away, but we should keep as few wild branches of this project as possible, since everyone randomly installing openiboot just for kicks (especially a modified version) and then coming to us (read: me, ultimately) for support is something we don't have the resources to handle at this moment.

On the porting side, the issues with installation, optimizing NOR access on iPhone 3G, NAND access on a few devices all seem to have been fixed, so we can basically scratch the first two items off of the list I put up in the last post. I'm pleasantly surprised at how relatively easy it was.

Anyway, now for the kernel. Well, if I don't get distracted by writing to NAND.

May 18, 2010

Debian on iPhone Linux

NAND writing is now semi-reliable (although one has to be VERY careful not to interrupt the device in the middle of a write operation), but it is enough to have something akin to a full-functional OS, backed by non-volatile storage.

People interested in the project should be familiar with the myriads of Linux "distributions" floating around. An operating system consists of two major domains: one is the kernel, which is what manages the hardware, and one is the userland which contains things like shells and other UIs, package managers, etc. Software that help users install and run useful programs. Ubuntu is a popular distribution that I run on my personal machine. Android could also be considered a distribution (though I believe it has some apparently messy kernel patches).

I decided that Debian would be an interesting thing to try, since we would then instantly have a userland and a pool of ready-compiled applications. Using a slightly dated root filesystem here: http://lists.debian.org/debian-arm/2007/01/msg00034.html, a initrd and further kernel configurations were sufficient to get it to run. Thus, we can now compile programs for iPhone Linux on iPhone Linux. The process is rather slow due to the processor and inefficient NAND device driver (pending a real FTL), but at least theoretically, iPhone Linux is now self-hosting.

This should be pretty much enough for those who are more into the userland development side of things to come in, possibly using Debian as a base to build anything else (as I believe it is standard enough).

I will be offering instructions on how to get this all to work soon. The (modified for gadget serial terminal) rootfs is fairly hefty (around 130 MB), so I'm not sure how we'll handle distribution of that.

May 17, 2010

Starting iPhonelinux Wishlist

Planetbeing's words from the iphonelinux github:
"This is just my personal WISHLIST. You might have different priorities. If you want to help, just submit patches that you think are helpful. If you need ideas, just refer to this list. Take it off the list in your patch when you finish something off the list. I'll try to give as much help and guidance as I have time to (which may not be much). 
This is not an exhaustive list, but just stuff I think people can actually deliver on reasonable timescales. For example, notice the conspicuous absence of "figure out how to make phone calls". It's roughly divided based on skillset.  
Jobs for C coders that may not have much RE or driver experience:  
1. Simplify driver code: An early goal of this project is to remain faithful to how the iPhone firmware operates the hardware. Some of it does not actually make sense or is otherwise not very efficient. We have a better understanding of the hardware now and can afford to write better drivers with that understanding. This is essentially refactoring.  
2. Refactor openiboot: I'm not sure I like the way openiboot is laid out right now. There's got to be a neater way to organize this. I'd like something that has less messy defines and a more consistent style so it's easier to read, perhaps individual folders for each module, and the ability to easily include or not include any individual module. An emphasis should be put on ease of porting. 
3. Add multitasking: A great project for students in or just out of OS classes. I've been too lazy to add true multithreading primitives: mutexes, semaphores, condition variables, and also multitasking in general. A lot of stuff is run in interrupt contexes or interrupt-disabled contexes. Writing drivers requiring blocking I/O is a pain. It's time for a true multitasking kernel. Should be done in coordination with #2.  
4. Write a gdb stub for openiboot: Those things are tiny and it shouldn't be that bad. Just have it communicate over the existing USB driver now. We wouldn't be able to debug interrupt contexts for now, but it's better than nothing.  
5. Someone needs to MAINTAIN the build script for the toolchain. Or else figure out if/how we can just build everything using Apple's or the community's iPhone OS toolchain. I'm pretty sure we can. It's not like we use the elf wrapper currently.  
6. It might be cool to be able to parse the iPhone's own device tree for some of base addresses. Might make porting less of a pain.  
7. With help from CPICH, we've determined the vibrator and speaker controls are in the baseband, both controlled through the at+xdrv command. Knowing this, the next step is to make sure we can talk to the baseband through the UARTs. This shouldn't be that bad since iBoot used to do it, and we already have UART code.  
8. I've implemented the firmware upload part of Libertas WLAN driver for Marvell 8686 to test out the SDIO functionality. It appears to work. Therefore, we have validated readb, writeb and writesb. More of it should be implemented to validate SDIO device interrupt handling and also readsb. After that, we will definitely have enough to support working wi-fi in the Linux kernel!  
Jobs for people who want to get their hands dirty with drivers:  
1. Look at TheSeven's NAND FTL code in Rockbox and CPICH's reverse engineering efforts to figure out the FTL write code and get it working.  
2. Write a new USB driver: I hate the current one. TheSeven might have some better code.  
3. Can we steal some code from that userland bluetooth stack and put it on top of our UART code? It might be even cleaner than USB, ironically, since we can probably do it all without interrupts.  
Jobs for reverse engineers:  
1. Port openiboot to unsupported platforms like ipt2g, ipt3g and iPhone 3GS.  
 2. For some reason, the NAND chips stop working after the iPhone is on for a long time. They're fine after a reboot. Figure out why that's happening.  
3. Get multitouch working for Zephyr2. It's a subclass of the Zephyr1 that I investigated, and at least some functions are shared, so it shouldn't be terrible.  
4. Figure out how to talk to the light sensor. It's a TSL2561 according to the ioreg. The slave address is 0x92/0x93 according to the ioreg "reg" setting and is one of the slave addresses allowed on the TSL2561. It's on i2c0 according to ioreg. It all looks good except for the fact I cannot get a response out of this part. I even bruteforced all the slave addresses on i2c0 and only got responses from the PMU, the accelerometer and the Wolfson, stuff we already know how to talk to. What's going on? Is it just my 2G is broken?  
5. Figure out the new FTL they're using on the newer devices. That's going to be a pain.  
Thanks for reading all this. I'm impressed."

May 16, 2010

The iPhone Porting Guide

Something helpful for those who are interested (but don't know where to start) in the "porting openiboot to other devices" task under "Jobs for Reverse Engineers".....

Base addresses, GPIO ports, i2c slave addresses, interrupt numbers, clock gates, etc. will all be available from ioreg -l on your jailbroken device. Check your ioreg -l output with the ioreg -l / device tree outputs of already ported platforms to see quickly which drivers are likely to be compatible with merely some constants changed, and which will need to be rewritten.

If you have an iPhone uart cable, you can port the uart driver early… it’s very simple. This will save you a lot of pain debugging.

Step 1. Figure out how to reboot the device. This is usually done by writing a value into a WDT register, but could be verified by reversing cmd_reboot in iBoot.

Step 2. Change the “Constants” in includes/hardware/s5l8900.h to reflect the basic memory layout of your hardware if necessary. Most likely this does not need to be changed provided the MIU was properly configured before openiboot is called.

Step 3. Make sure PeripheralPort in includes/hardware/s5l8900.h is set to the right place. You can find out by reversing iBoot and finding where it sets the peripheral port remap register early on.

Step 4. Figure out where the MIU configuration register is and which MIU setting to use to make sure SDRAM is mapped to 0×0. This can also be most likely found in iBoot. The MIU is one of the devices labeled /arm-io/clkrstgen in the iPhone’s device tree. Change the instructions at the beginning of entry.S, miu_setup, and clock_set_bottom_bits_38100000 with this new information. You may attempt to make the assumption that the MIU is still at the same place and/or has the same register offsets/values.

Step 5. Put a reboot early on in entry.S and progressively move it back, troubleshooting as you go, until you reach C code (OpenIBootStart). This is the first major landmark.

Step 6. Port over clock.c, power.c, timer.c, interrupt.c and the interrupt handling code in entry.S. Most likely you just need to change the base addresses in their respective includes/hardware/*.h. Use the event.c code (which is platform independent) to try to schedule a reboot 10 seconds after you launch openiboot. (make sure you comment out everything you haven’t ported and add a while(1); at the end of your code). If this works, the timer, clock and interrupts all work. These are very important basic services for the other drivers. Use a combination of the reboot code you worked out in step 1 and while(1)s to troubleshoot, they will be your only form of feedback for now.

Step 7. Port over usb.c. Again, you can probably just change the base address of the USB code and it will work. Once that is done, you can re-enable all the command line parsing code. If the openiboot command line code works, then you have a basic bring-up!

Step 8. Port over the GPIO driver. You can test its workings by checking the button states. You need this for a whole bunch of devices.

Step 9. Port over the i2c driver. Test with the accelerometer. This is needed for the PMU and LCD among other things.

Step 10. Port over the pmu driver. This is a good application of the i2c driver, and you need it to control the backlight.

Step 11. Port over the SPI driver. Most notably, this is used for the LCD driver and probably NOR on new ports. No easy way to test this in isolation so you’ll want to do it concurrently with step 13.

Step 13. Port over the NOR driver. It might “just work” when the SPI driver does.

Step 14. Port over the LCD driver. This is probably one of the trickier parts. I had to check the actual iBoot disassembly for my ports here. However, it only took an hour or so to get working.

Step 15. Port over the DMA controller. There probably won’t be any changes, but who knows.

Step 16. Port the rest. There aren’t any surprise dependencies. sdio → wan, radio → uart and that’s about it.

May 15, 2010

Top Study Tips For First Year Students

Android running on iPhone!

I've been working on this quietly in the background. Sorry about the initial video quality, but YouTube promises that the quality will get better as the video gets processed more. The back part of the version I uploaded to Vimeo was cut off.



I think that says it all, really. Donations via paypal to planetbeing at gmail.com. If you'd like to help, come join #iphonelinux on irc.osx86.hu.

Thanks to CPICH for reversing support, harmn1, posixninja, jean, marcan and saurik for patches, and last but not least, TheSeven for his work on the FTL.

Pre-built images and sources at http://graphite.sandslott.org:4080/pub/idroid/idroid-release-0.1a.tar.bz. Read the README. For generic openiboot instructions, there's plenty now that you can search for.

It should be pretty simple to port forward to the iPhone 3G. The 3GS will take more work. Hopefully with all this groundwork laid out, we can make Android a real alternative or supplement for iPhone users. Maybe we can finally get Flash. ;)

EDIT: Apparently on some iPhones, the installation of openiboot appears to be failing (THIS MEANS IT WON'T BOOT UP AGAIN). This is being investigated (I can't reproduce it on my own phone), but meanwhile you can just do a "tethered boot". In openiboot console, don't install but do !zImage, kernel, !android.img.gz, ramdisk, boot "console=tty root=/dev/ram0 init=/init rw" (after installing the other images to the second partition). If your phone won't boot up again, a DFU restore will get it back to normal. Take a deep breath. Calm down. There's nothing to worry about. :) We'll get this sorted out by tomorrow.

EDIT2: Fixed! It was previously only working on phones that used PwnageTool due to some assumption I made. Thanks geohot! Redownload the archive or just openiboot.img3

May 14, 2010

A New iPhone A to-do list

I'm gratified at a lot of the developers that want to help! This is the only way this project can stay alive. That being said, let's start to get a little organized. Here's a to-do list:

http://theiphonewiki.com/wiki/index.php?title=IPhoneLinux_To-Do

I'm proposing that unless someone wants to step in to host and administer an iPhone Linux website/wiki/forums, we use the iPhone Wiki to exchange information since it's there already. That said, Be Bold and work on whatever you like! If you have patches to openiboot, send them using git. If you have patches for the kernel or Android stuff, just contact me with it (IRC preferred, e-mail is okay) and I'll see about how we can publish them.

I'll personally be focusing on the first gen iPod touch and 3G port since I think I have a comparative advantage in that area.

Free Google Maps Navigation App Coming to iPhone

Google working on bringing free nav app to other platforms than Android

Smartphones are highly converged devices that offer users the ability to surf the web, talk, text, and take pictures. One of the more popular uses for smartphones today is as GPS navigation devices. Most platforms have GPS applications that require the user to purchase the app or pay a monthly fee.

Google unveiled a free GPS navigation platform for its Android devices in October of 2009 that provided free GPS navigation services in America. The platform recently landed in Europe for free as well. Along with the move into Europe, Google has announced that it intends to extend its free Google Maps Navigation service to other platforms.

Those other platforms include the iPhone. Getting its free GPS navigation platform onto the iPhone would be huge for users. TomTom, Navigon, and other providers on the iPhone right now charge $60 or more for GPS applications and some like AT&T charge a monthly fee for GPS navigation.

The launch of Google Maps Navigation in Europe is a big deal; Europe was left out of the launch last year. UK users can get Google Maps Navigation on their Android device as a free update to Google Maps.

“Google Maps pre-caches the entire route,” said Mobile Maps product manager, Steve Lee. “It needs a data connection when you ask for navigation. But while driving to your destination, if you intermittently lose the connection, it will still carry on. As long as you stay on the route.”

The free GPS service will undoubtedly hurt paid offerings from companies like Garmin and TomTom in the UK. Google simply says that other providers had become stale and its offering will force them to innovate in the GPS market.

May 13, 2010

The port to the iPhone 3G

The port to the iPhone 3G is coming along. This is a picture of an iPhone 3G booting into a BusyBox / Buildroot shell. As you can see, wireless networking is working great. We can also talk to the baseband over the debugging channel. This might be enough to get calling, etc., working but we may need to figure out the SPI transport.

I'd still like to get the WM8991 codec working for it in openiboot (shouldn't be much trouble since there's a datasheet), just so we can iron out any quirks before testing it inside the kernel. We also need a new multi-touch driver (they've upgraded from Zephyr to Zephyr2). After that, we'll have a working port of Android.

Also, for existing developers and testers, I've implemented the Android wi-fi driver extensions so WLAN should be working better now. I know people had problems associating with WPA protected networks, etc. See if this update helps!

May 12, 2010

Android repos are up

We've gotten a tremendous response -- far more than I've actually anticipated before the release. I would like to thank the community for their interest. The amount of support and enthusiasm that was displayed was truly humbling to someone used to cynicism about this project.

The thing I'm most excited about is the fact there are now many developers working on several different things... a pretty big change from when I was hacking on the source tree virtually alone. There are developers actively working on the first generation iPod port, the iPhone 3G port, and a second-generation iPod touch port and things are moving much more quickly than I've anticipated. With so many helping hands, I'm sure that we can get these ports to production quality.

To coordinate our efforts, I've setup a series of git repositories on GitHub. You can clone the Android tree using Google's repo tool thus:

repo init -u git://github.com/planetbeing/platform_manifest.git -b android-sdk-1.6_r2-iphone


This command populates the majority of the tree from the main Android kernel.org repositories, with any changed project from my tree.

git://github.com/planetbeing/kernel_common.git branch android-2.6.32-iphone is our kernel tree. It is included in the main repo checkout as well.

git://github.com/planetbeing/iphonelinux.git as always is our openiboot/bootloader tree. New hardware support will be trialled there and then ported into the Linux kernel.

A fellow with the nickname of "konaya" on IRC has volunteered to administer a website for us at http://www.idroidproject.org. We can use the wiki to document iPhone Linux/iDroid and the forums to provide help to newcomers. We also have a developer mailing list (please ask in IRC if you wish to get added to that).

May 11, 2010

New iPhone 3G Multi-touch

I finished writing a driver for the Zephyr2 on the iPhone. It's the same multi-touch solution that Apple has used starting from the first generation iPod touch and up to and including the iPad.

Now, of course this shouldn't be construed as a promise to support the iPad eventually, but this multi-touch driver is definitely a concrete milestone that is important for pretty much all of Apple's mobile Internet devices.

More immediately, this is pretty much the sole remaining blocking issue on the first-gen iPod touch and one of the two major issues on the iPhone 3G. The other issue on the iPhone 3G is baseband SPI. I'm wondering if we can get away with just using the debug uart to make calls (if we don't care about having a fast 3G data connection yet).



Also, I'd like some opinions from this blog's readers: More frequent updates? Or just document the major advances?

May 10, 2010

Creating a WM8991 driver

Thought it might be interesting for people to take a peek at how we work.

As I stated in the previous blog post, it's necessary for us to figure out the WM8991 audio codec before we can call from the baseband (or listen to music). This is an interesting task because while there are datasheets for the WM8991 codec, and a Linux driver for it, those cannot be used immediately since it doesn't tell us where the inputs and outputs of the chip are connected to, and what protocol and clock divider settings the iPhone uses to talk to the chip (and must be configured on the chip). Those things are purely implementation specific.

In order to extract those settings, we need to be able to see those settings while the iPhone OS kernel is up and running and sound is playing. The chip does not use MMIO, so the register settings cannot be directly peeked at through /dev/kmem... but we're on the right track. Instead, I2C is used to communicate with the codec for setting those registers. It turns out that since some Wolfson codecs do not allow reading from the codec registers (only writing), the operating system has to "remember" what values registers are currently set to. That is, they are cached by operating system?

Where are they cached? Well, a quick look at the disassembly shows us some code that does the following (in pseudo-C)


if register > *(this + 0xA0)
return 0

return *((uint16_t*)(*(this + 0xA8) + register * 2))


Basically, we see that the class member at offset 0xA0 contains the total number of registers accessible on the Wolfson codec, while member 0xA8 is a pointer to an array of 16-bit values that represent the current values of those registers!

Now we seem to be home free... except for the fact that IO Kit C++ objects are dynamically allocated on the heap at runtime and there is no way to tell using static analysis where they will be during a particular boot of an operating system. How will we find the location of this C++ class (AppleWM8991Audio) so that we can peek at those values?

The answer is that every object in the IOKit subsystem is anchored to the IORegistry tree. You can actually take a peek at the tree from userland with the ioreg -l command. Every single node you see corresponds to a C++ object. However, the trouble is that there is no userland call to extract the in-kernel addresses of those objects... and that's what we need to be able to use /dev/kmem to peek at the right places.

Fortunately, the root of the IORegistry is pointed to by a constant, and it is possible to traverse the IORegistry manually from the root (provided you know the layout of all the C++ classes!). This is exactly what I wrote a utility called spelunk to perform: use /dev/kmem to manually traverse the IORegistry and find the in-memory instance, instance size, and vtable location of all of the objects in the IORegistry. Armed with this information, one can use dd and /dev/kmem to peek at the state of any of the objects inside kernel memory.

May 9, 2010

MapQuest Offers Voice Guidance in Free iPhone App

MapQuest Offers Voice Guidance in Free iPhone App
Before now, only Android users were able to take advantage of free turn-by-turn navigation from their phone.

iPhone users, now its your turn.

Through its official blog, MapQuest announced yesterday the inclusion of voice guidance in the latest version of its free iPhone app.

In the post, MapQuest principal product manager Michael Iams describes a trip he took from his Las Vegas hotel to the airport with help from the new application. Basically, users search for the location they are interested in then press the Start button to begin navigation. Whenever you hit a detour or miss a turn along the way, the application brings up a prompt with a button that reads “Reroute me.

Iams also mentions that the app doesn’t waste the phones power, dimming the screen during navigation and allowing the user to customize energy settings.

Other than Google Maps on Android 2.0 phones, the MapQuest app is the only free turn-by-turn navigation app available and the only one for the iPhone, so do check it out.

May 8, 2010

Opera Mini Approved for iPhone! Yes, That is Right!

Apple does the unthinkable and approves Opera Mini for the iPhone, iPod touch

In what must be one of the most shocking developments in the whole Apple App Store versus the third-party app market comes news that Opera Mini has been approved by Apple for the iPhone and iPod touch. When Opera Software submitted the apps for Apple's prying eyes back in March, no one really took them seriously and thought that they were just showing off to drum up some press.

Well, Apple has shown Opera some leniency and Opera Mini will be available to U.S. iPhone and iPod touch users shortly. Here's the Opera press release in its entirety:

Opera today announced its popular mobile browser, Opera Mini has been approved for iPhone and iPod touch on the App Store. Opera Mini will be available as a free download within 24 hours, depending on market.

Opera Mini, with more than 50 million users worldwide, enables fast mobile Web browsing by compressing data by up to 90 percent before sending content to the device, resulting in significantly improved page loading. Users of the app will notice an uptake in speed, especially on slower networks such as the 2G Edge network. Surfing the Web with the Opera Mini App on iPhone and iPod touch will also help users save money because of its data compression capabilities. This will hold especially true while the user is incurring roaming charges.

"We are delighted to offer iPhone and iPod touch users a great browsing experience with the Opera Mini App," said Lars Boilesen, CEO, Opera Software. "This app is another step toward Opera's goal of bringing the Web to more people in more places."

The Opera Mini App is available for free from the App Store on iPhone and iPod touch or at www.itunes.com/appstore

Could the walls be crumbling in Apple's heavy-handed approach to App Store acceptance/rejection? Maybe Opera just caught Steve Jobs on a good day. Who knows, but this is at least a good step forward for Apple.

May 7, 2010

iPhone OS 4.0 Will Bring Multitasking, iAd, Social Gaming Network This Summer

Third-party multitasking finally makes an appearance on the iPhone

It's been just over a year since Apple last held an event touting the latest and greatest version of its iPhone OS. In March 2009, the big features that Apple brought to the table with iPhone OS 3.0 included copy/paste, push notifications, and push notifications (to make up for the lack of third-party multitasking).

Today, Apple is back at it again with iPhone OS 4.0. As has been widely speculated for the quite some time now, Apple is finally enabling third-party multitasking on the iPhone OS (iPhone, iPod touch, iPad). As the rumors suggested, double tapping the home button now brings up a “multitasking dock” which shows up to four programs running at once (here's a video of multitasking in action). The user then selects the application they want and "boom", you're there. As you would expect, the current application state is saved as you're double tapping in and out of apps.

For a demo, Apple's Scott Forstall showed off an app that has probably been the poster child for the multitasking movement on the iPhone: Pandora. Previously, if you wanted to listen to streaming music in Pandora while performing another task, it wasn't possible (without jailbreaking). The new multitasking APIs of iPhone OS 4.0 now make what seems like a no-brainer feature possible. As an added bonus, Pandora can now be controlled from the lock screen.

May 6, 2010

An introduction to the blog Makawa

Sometimes, I like to write down my thoughts about stuff. My graphomania tends to be sporadic, but it is nice to have a place where I can exercise it when I experience it. The dev team has a bit of a taboo against blogging, which is why I haven't done it before. "Code, not ego" is our creed, and some of us believe that blogging sometimes lead to the interests of the community or the team being compromised in order to gain attention. However, I don't see anything wrong with sharing some of my love for the art... as long as I practice discretion and good taste.

Besides, we have an "official blog" now, so I feel like the playing field is open. ;)

This blog is for the developers of iPhone Linux. Any developer who's working on the project (sadly, a very short list of individuals) can ask me for write permissions here. The format will be kept largely informal. Major announcements and technical information will go on the wiki, but I'll personally be dumping a lot of technical information here on the blog as well when I can't decide/can't be bothered to condense and format it for the wiki. Views represented here are of the individual developer and not of the project in general.

Let me introduce myself though: Hi, I'm planetbeing. I'm currently, I suppose, the lead developer on the iPhone Linux project by virtue of circumstance. I was introduced to this project by cmw, a hacker who has a ton of experience porting Linux and other operating systems to a variety of equipment in the past. Unfortunately, he's currently largely burdened with other commitments. Even so, he helps out as much as he can, and he has some very exciting projects bubbling in the background that I'm sure you'll hear about soon. :)

I'm also a member of the iPhone Dev Team. While iPhone Linux has not official or direct connection with the Dev Team (I just happen to be on the Dev Team and also working on this project), its members often lend me valuable insight into many, many problems. Remember, less than a year ago I hadn't reversed a single line of code. I brought to the table (I hope) a quick and ready mind but only by hanging out with them was I able to fill it so fast.

Lastly, I tend to be overly locquacious in writing. Honestly, most people have one paragraph introduction posts and this is already War and Peace. For that, I apologize and I hope you will stick with me nevertheless.

My next post will be entitled "Why iPhone Linux?" It's something I often am challenged on and I thought I would write up an article justifying all the time I'm spending on it. :)

First iPhone Application

Introduction
In this tutorial I will give you a brief introduction on how to get started with your first iPhone application. To begin you will need the latest version of the iPhone SDK which you can download it from here. With the SDK you get some tools like Xcode, Interface Builder, iPhone simulator, and many more. The first application is usually called "Hello World" but I have named my first app "Hello Universe" because a revolutionary device calls for a change of name.

Purpose of the "Hello Universe" app
Using the app a user will be able to enter his/her full name and click a button to see a message appear. The message will say "John Doe says Hello Universe!!!". This app will not only introduce you to some of the tools but will also show you how to use controls, respond to events and create new views. Excited, I am :-)

This is how the app will look like

Creating a new project
Launch Xcode and click on File -> New Project -> Select Application (under iPhone OS) -> select Window-Based Application project template and click on choose.

In the next screen you will be asked to save your project and give it a name. Xcode creates some files for us based on the name of the project, so you want to be careful with the name you provide. I have named my project "HelloUniverse".

This is how the list of files look like in Xcode.

All the class files are stored under the "Classes" folder, some special files are listed under "Other Sources", all the view files and resources show up under "Resources", and any library or frameworks we add to our project are listed under the "Frameworks" folder. It is important that we save all the images, files, databases, and views in the "Resources" folder because all the iPhone apps run in its own sand box; which means they can only access files placed under the resources folder.

How the app is launched
Every C/C++/Java/C# programmer knows about the main method found in main.m file which is present under the "Other Sources" folder. You normally will never have to change this method and all we have to know is that this method is responsible in launching the app. The method applicationDidFinishLaunching method is called when the app is launched on the device or the simulator. The method is defined in "HelloUniverseAppDelegate.m" file which is found under the "Classes" folder.

Interface Builder
Using Interface Builder we can design our application by adding controls or creating additional views. The files that the Interface Builder creates gets saved with a .xib extension and are called nib files. Every project gets one nib file by called which is called "MainWindow.xib" which can be found under "Resources". An iPhone application has only one window (MainWindow.xib) unlike a desktop application which is created with multiple windows; however, we can create multiple views which are added to the window. Double click on "MainWindow.xib" to launch the Interface Builder, which will open four windows and one of the window will look like this


The above picture shows the contents of the "MainWindow.xib" nib file. Every nib file has atleast two files; File's Owner and First Responder which cannot be deleted. Every other objects apart from the first two, represents an instance of an object which gets created when the nib file loads. File's Owner simply shows that it owns the object in the nib file. First Responder tells us which object are we currently interacting with; like the textbox, buttons... The third object which is special to the MainWindow.xib file is called "Hello Universe App Delegate" and this file represents "HelloUniverseAppDelegate" class. Last but not the least the view represents the object which we design in our apps.

Creating a new view
If we had created this project using "View-Based Application" project template then there would have been no need of creating another view from scratch, but where is the fun in that. In Interface Builder create a new view by clicking File -> New -> Select Cocoa Touch -> View and click on choose. Let's save the view in the project folder by naming it "HelloUniverse" and once we do that IB (Interface Builder) will prompt us to add the view to the current project; click on "Add" and it will show up in Xcode. In Xcode and move your view to the Resources folder.

Creating a view controller
We have a view now let's create a view controller to manage the view. In Xcode create a new view controller by selecting classes and clicking File -> New File -> Select Cocoa Touch Classes under iPhone OS -> select UIViewController -> click on choose and name your file "HelloUniverseController" without changing the extension. The newly created class inherits from UIViewController which knows how to interact with a view. Now that we have our view and the controller class, there must be some way to connect these two files and we can do it by setting the class property of the File's Owner. Double click "HelloUniverse.xib" file in Xcode to launch Interface Builder and select File's Owner -> select Tools -> Identity Inspector and under "Class Identity" category, change the class to "HelloUniverseController". This is how the Class Identity should look like


Once that is done we need a way to control the view in the nib file from code and this is done by connecting the view instance variable to the view object in the nib. The connection is made using "outlets". Select Tools -> Connections Inspector create a connection from the view variable to the view in the nib file. Move your mouse over the empty circle to see it change to a plus symbol indicating that a connection can be created. Click on circle and drag your mouse to the view in the nib file and release. As you do this you will see a blue line being created from the circle to the mouse. Once a connection is created, the connections inspector for File's Owner will look like this


Adding controls to the view
From the screen shot above we require two text boxes, one label, and a button (Round Rect Button). From the library drag and drop the controls to the view and align it as seen in the figure 1.0. After you have added the controls let's change some of its properties, starting with the text boxes. Select the first text box and open Attributes Inspector by selecting Tools -> Attributes Inspector. Under Placeholder enter "First name", under "Text Input Traits" change Capitalize property to "Words" and change the Return key property to "Done". Apply the same settings for the other text box but change the Placeholder to say "Last name". Select the label and delete its text property, since we do not want the label to say anything until the button is clicked. Double-click the button to edit the title of the button and type in "Click Me". Save and quit Interface Builder as we have successfully designed our view.

Connecting instance variables to the objects in the view
We still need some way to interact with the controls on the view, in code and this is where outlets help us out. IBOutlet is a special keyword if used with an instance variable, will make the variable appear in Interface Builder. Since IBOutlet makes the variable appear in Interface Builder, using IBAction as a return type for a method will have the opposite effect. Using IBAction we can handle an event triggered by any control placed on the view. Let's see how this works; open HelloUniverseController.h file in Xcode and type in the following code

//HelloUniverseController.h
@interface HelloUniverseController : UIViewController {

IBOutlet UITextField *txtFirstName;
IBOutlet UITextField *txtLastName;
IBOutlet UILabel *lblMessage;
}

- (IBAction) btnClickMe_Clicked:(id)sender;

@end

//HelloUniverseController.m
- (void)dealloc {
[txtFirstName release];
[txtLastName release];
[lblMessage release];
[super dealloc];
}

All the variables above are marked with IBOutlet and Interface Builder will make these available to itself so proper connections can be made. We also have a method whose return type is IBAction (void); Interface Builder will also make this method available to itself so we can choose which event will call this method. The method also takes a parameter called "sender" which is the object which triggered the event. The variables are released in the dealloc method as shown above. Let's connect these instance variables to the controls on the view (HelloUniverse) as described earlier. Open Interface Builder by double-clicking HelloUniverse.xib file and select File's Owner, open Connections Inspector to see all the variables present under Outlets and to create connections.


Let's hook up the button click event to the "btnClickMe_Clicked" method. Select the button and under the Events list it seems that we do not have a button click event; however, we do have a "Touch Up Inside" event which is raised when the button is touched and released symbolizing a click. With the button selected click the circle next to "Touch Up Inside" and drag your mouse over to File's Owner and release to have the method name show; simply click on the method name to create a connection.


Handling events
Let's write some code in btnClickMe_Clicked event to read the first and last name and display a message in the label. This is how the code looks like

//HelloUniverseController.m
- (IBAction) btnClickMe_Clicked:(id)sender {

NSString *FirstName = txtFirstName.text;
NSString *LastName = txtLastName.text;
NSString *Message = nil;

if([FirstName length] == 0 && [LastName length] == 0)
Message = [[NSString alloc] initWithFormat:@"Anonymous says Hello Universe!!!"];
else if ([FirstName length] > 0 && [LastName length] ==0)
Message = [[NSString alloc] initWithFormat:@"%@ says Hello Universe", FirstName];
else if ([FirstName length] == 0 && [LastName length] == 0)
Message = [[NSString alloc] initWithFormat:@"%@ says Hello Universe", LastName];
else
Message = [[NSString alloc] initWithFormat:@"%@ %@ says Hello Universe", FirstName, LastName];

lblMessage.text = Message;

//Release the object
[Message release];
}

The method does few simple things, it finds out the first and last names and figures out what message to display in the label. We also create a temporary variable called "Message" to hold the message which will be displayed in the label. The variable is allocated and initialized by alloc and initWithFormat messages respectively. The variable is released in the end because when working with the iPhone we are responsible of cleaning up the memory. The easiest way to remember when to release objects is; if you create it then you own the object and hence you are responsible of releasing it.

If you click on Build and Go, the view will not be visible because we have not yet added it to the window. Let's see how we can do that

Adding view to the window
Now we cannot drag the view and add it to the window, so we need another way to add the view as a sub view to the window. We already know that "HelloUniverseController" is the view controller of the view "HelloUniverse" and "HelloUniverseAppDelegate" is the application delegate where the window is made visible in applicationDidFinishLaunching method. It is in that method we will add the view as a sub view to the window. Before we do that, the application delegate (HelloUniverseAppDelegate) needs to know about our view controller. Add the following lines to HelloUniverseAppDelegate.h file to change the file like this

//HelloUniverseAppDelegate.h
@class HelloUniverseController;

@interface HelloUniverseAppDelegate : NSObject {
UIWindow *window;
HelloUniverseController *hvController;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) HelloUniverseController *hvController;

@end

From the above code we first add a forward class declaration of "HelloUniverseController" because we do not want any circular dependency when we import the header file of "HelloUniverseController" in HelloUniverseAppDelegate.m. A variable and a property of type HelloUniverseController is also declared. The property as you can see is declared with a couple of attributes called "retain" and "nonatomic". The retain attribute will increase the reference count of the instance variable by one and nonatomic is used because our program is not multi-threaded.

A lot of first time users miss to synthesize the property we declared, so let's do that now at the top of the HelloUniverseAppDelegate.m file and the code looks like this


//HelloUniverseAppDelegate.m
@implementation HelloUniverseAppDelegate

@synthesize window, hvController;
...


The view is added as a subview to the window in applicationDidFinishLaunching method and this is how the code looks like

//HelloUniverseAppDelegate.m
- (void)applicationDidFinishLaunching:(UIApplication *)application {

HelloUniverseController *hvc = [[HelloUniverseController alloc]
initWithNibName:@"HelloUniverse" bundle:[NSBundle mainBundle]];

self.hvController = hvc;

[hvc release];

[window addSubview:[self.hvController view]];


// Override point for customization after application launch
[window makeKeyAndVisible];
}

The second line shows that we imported the header file of "HelloUniverseController" and we also synthesized the property hvController. In the "olden" days in order to create a property we had to create getter and setter methods which would be something like getHVController and setHVController. The synthesize keyword automatically generates these methods for us. In applicationDidFinishLaunching method we allocate and initialize a temporary variable, assign it to our property, release it, and the view associated with the view controller is added as a sub view to the window. The key thing to remember here is that the view message is passed to the "hvController" which returns the view and is added as sub view to the window. A valid view is returned because we created a connection from the view instance variable to the view in the nib file. The property is finally released in the dealloc method as shown below

//HelloUniverseAppDelegate.m
- (void)dealloc {
[hvController release];
[window release];
[super dealloc];
}

We have always allocated and initialized variables in one single line as seen below, this is usually the accepted way but the same code can be written in a different way as seen below

HelloUniverseController *hvc = [HelloUniverseController alloc];
hvc = [hvc initWithNibName:@"HelloUniverse" bundle:[NSBundle mainBundle]];

Build and go to test your application.

Hiding the keyboard
Wait a minute clicking the "Done" button doesn't do anything. Ideally we would like to hide the keyboard when the "Done" button is clicked no matter which text box we are currently editing. To hide the keyboard we need to do two things; set the delegate of the keyboard to File's Owner and implement a method called textFieldShouldReturn in HelloUniverseController.m file. To set the delegate, open Interface Builder by double clicking HelloUniverse.xib, select the first text box and click on Tools -> Connections Inspector. Click and drag your mouse by selecting the empty circle next to delegate under "Outlets" and release your mouse over to File's Owner. Assign the delegate for the next text box in the same manner.

The method textFieldShouldReturn gets called when the "Done" button is clicked and this is how the code looks like

//HelloUniverseController.m
- (BOOL)textFieldShouldReturn:(UITextField *)theTextField {

[theTextField resignFirstResponder];
return YES;
}

The method gets a parameter called sender, which is the object that triggered the event. We will use the same object to which we send the resignResponder message, which will hide the keyboard on the textbox. The boolean "Yes" is returned to tell the sender that the first responder is resigned.

Conclusion
I hope you had fun with this tutorial and feel a little confident in writing your next great iPhone app. Please leave me your comments and let me know what you thought.

Happy Programming,
iPhone SDK Articles

PS: I have re-written this tutorial hoping it would be easier to follow. If you have any questions please do not hesitate to send me an email here and I will be happy to help you out.