/*
Build_LinuxOS - for building a boot2 compatible Linux image
Copyright (C) 2013 Daniel Tang
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include
#include "atag.h"
extern const unsigned char initrd[];
extern const unsigned int initrd_size;
extern struct atag atag_list;
void __attribute__((noreturn)) kernel_begin(int zero, int mach, void *param);
void __attribute__((noreturn)) panic(void);
typedef volatile unsigned short *io16_port;
typedef volatile unsigned int *io32_port;
int is_cx = 0;
int mach_type = 0;
uint32_t mach_rev;
uint32_t ram_size;
uint64_t serial_num;
#ifdef DEBUG
void nputs(const char *ptr) {
io32_port serial = (io32_port)0x90020000;
unsigned char c;
while ( (c = *ptr++) ) {
serial[0] = c;
if (is_cx) {
while (serial[6] & (1<<5));
} else {
while (!(serial[5] & (1<<5)));
}
}
}
#else
#define nputs(x)
#endif
void nstrcpy(char *dst, const char *src) {
while ( (*dst++ = *src++) );
}
void build_atags(void) {
struct atag *current = &atag_list;
current->hdr.tag = ATAG_CORE;
current->hdr.size = 2;
ATAG_NEXT(current);
current->hdr.tag = ATAG_MEM;
current->hdr.size = 4;
current->u.mem.start = 0x10000000;
current->u.mem.size = ram_size;
ATAG_NEXT(current);
current->hdr.tag = ATAG_REVISION;
current->hdr.size = 3;
current->u.revision.rev = mach_rev;
ATAG_NEXT(current);
current->hdr.tag = ATAG_SERIAL;
current->hdr.size = 4;
current->u.serialnr.low = serial_num;
current->u.serialnr.high= serial_num>>32;
ATAG_NEXT(current);
current->hdr.tag = ATAG_CMDLINE;
current->hdr.size = 2 + ((sizeof(CMDLINE) + 3) / 4);
nstrcpy(current->u.cmdline, CMDLINE);
ATAG_NEXT(current);
#ifdef RAMDISK_SIZE
current->hdr.tag = ATAG_RAMDISK;
current->hdr.size = 5;
current->u.ramdisk.flags= 0;
current->u.ramdisk.size = RAMDISK_SIZE;
current->u.ramdisk.start= 0;
ATAG_NEXT(current);
#endif
#ifdef HAVE_INITRD
current->hdr.tag = ATAG_INITRD2;
current->hdr.size = 4;
current->u.initrd2.start= (uint32_t)initrd;
current->u.initrd2.size = initrd_size;
ATAG_NEXT(current);
#endif
current->hdr.tag = ATAG_NONE;
current->hdr.size = 0;
}
#define ADD_BITS(v,r,x,y) do { \
unsigned len = ((y)-(x)+1); \
v <<= len; \
v |= ((r)>>(x)) & ~(~0<>58) & 0x1F;
}
#undef ADD_BITS
void detect_mach(void) {
io32_port misc = (io32_port)0x900A0000,
clock = (io32_port)0x900B0000;
io16_port keypad= (io16_port)0x900000d8;
unsigned int model = *misc;
model &= 0x0fff;
if (model != 0x101 && model != 0x010) {
nputs("Could not detect calculator model. Panicking.\n");
panic();
}
if (model == 0x101) {
is_cx = 1;
ram_size = 0x04000000;
mach_type = 4443;
nputs("Detected as CX.\n");
return;
}
if (*keypad & (1<<0)) {
/* Keypad not plugged in? - probably a clickpad */
ram_size = 0x02000000;
mach_type = 4441;
nputs("Detected as Clickpad.\n");
goto classic;
}
/* Touchpad */
ram_size = 0x02000000;
mach_type = 4442;
nputs("Detected as Touchpad.\n");
goto classic;
classic:
/* Workaround for stupid serial timing bug in the kernel */
/* TODO: fix upstream */
clock[0] = 0xa1002;
clock[3] = 4;
return;
}
int main(void) {
detect_mach();
detect_serialnr();
build_atags();
nputs("Booting kernel.\n");
kernel_begin(0, mach_type, &atag_list);
}